Disabling Implicit Casting in c++ - c++

Is it possible to disable implicit casting in C/C++.
Suppose I want to write a validity function that makes me enter only integers in range [1,10]
I have written:
#include <iostream>
using namespace std;
int main( )
{
int var=0;
cout << "Enter a number (Integer between 1 to 10) : ";
while( (!(cin >> var )) || (var > 10 ) || (var < 1) )
{
cout << "U nuts .. It can only be [1,10]\n";
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
cout << "Enter a number (Integer between 1 to 10) : ";
}
cout << "\nYou entered : " << var;
return 0;
}
But if the user enters 9.5 it accepts it by converting the float 9.5 as 9 and storing it in var. I want any float entry to be treated as invalid entry. How do I achieve this most compactly.
I do not want to do something of this sort:
#include <iostream>
#include <cmath>
using namespace std;
int main( )
{
float var=0;
cout << "Enter a number (Integer between 1 to 10) : ";
while( (!(cin >> var )) ||(var < 1)|| (var > 10 ) || !(ceilf(var) == var) )
{
cout << "U nuts .. It can only be [1,10]\n";
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
cout << "Enter a number (Integer between 1 to 10) : ";
}
cout << "\nYou entered : " << var;
return 0;
}
This serves my purpose . But what I want to know, that is there any way where a conversion from float to int - I can suppress or it can show it as false input.
Similar to the way cin >> var where var type is int - if we enter char it returns false condition. Can we achieve the same for float entry ?
Thanks

But if the user enters 9.5 it accepts it by converting the float 9.5 as 9 and storing it in var.
No it doesn't. If the the user enters 9.5, then cin >> var stops reading when it hits the . (and leaves it on the stream). There's no float-to-int conversion because you haven't read a float, just an int.
The fix is to read the rest of the input (after cin >> var), and make sure there's nothing bad left over after the end of the int.

If you want to validate all of the input, you will have to get the whole line first.
Try:
string line;
getline(cin, line); // gets whole line
char *endptr;
long int var = strtol(line.c_str(), &endptr, 10); // converts string to int
// now check that endptr points to end of the string
if (endptr<line.c_str()+line.length()) {
// extra characters found after the integer
}

Related

how to make cin only take integer inputs

i new to programming and we are required to create a program that dont exit when the user inputs the wrong input, but i only learned the basics so far.. i already solved when the number is above and below 100 but when the user accidentally inserted a non integer it will go into a error loop. btw this is an average calculator.
#include <iostream>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
cout << "how many numbers will you input?: ";
cin >> n;
while ( n > 100 || n <= 0 )
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for ( int i = 0; i < n; ++i )
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
If std::istream::operator >> fails, it will set failbit. Therefore, you should check failbit (for example by calling std::cin.fail()) to see whether the conversion was successful, before using the result of the conversion.
If the conversion fails due to bad input, then the next call to std::istream::operator >> will automatically fail due to failbit being set. That is why you are getting stuck in an infinite loop. If you want to attempt input again after a conversion failure, you will first have to clear failbit, by using the function std::cin.clear().
Also, you will have to discard the bad input that caused the conversion to fail, because otherwise, the next time you call std::istream::operator >>, the conversion will fail again for the same reason. In order to clear the bad input, you can use std::cin.ignore(), like this:
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
In order to use std::numeric_limits, you will have to #include <limits>.
After performing these fixes on your code, it should look like this:
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int num[100];
int n;
double sum, average;
bool input_ok;
//repeat until input is valid
do
{
cout << "How many numbers will you input? ";
cin >> n;
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else if ( n > 100 || n <= 0 )
{
cout << "Error: Number should in range of (1 to 100) only!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
for ( int i = 0; i < n; ++i )
{
do
{
cout << i + 1 << ". Enter number: ";
cin >> num[i];
if ( cin.fail() )
{
cout << "Error: Conversion to integer failed!\n";
input_ok = false;
}
else
{
input_ok = true;
}
//clear failbit
cin.clear();
//discard remainder of line
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
} while ( !input_ok );
sum += num[i];
}
average = sum / n;
cout << "Average = " << average;
}
This program has the following behavior:
How many numbers will you input? 200
Error: Number should in range of (1 to 100) only!
How many numbers will you input? -31
Error: Number should in range of (1 to 100) only!
How many numbers will you input? test
Error: Conversion to integer failed!
How many numbers will you input? 4abc
1. Enter number: 1
2. Enter number: 2
3. Enter number: 3
4. Enter number: 4
Average = 2.5
As you can see, the program now works in that it can now handle bad input such as test. It rejects that input and reprompts the user for new input.
However, one problem with this program is that it accepts 4abc as valid input for the number 4. It would probably be appropriate to reject such input instead. One way to fix this would be to inspect the remainder of the line, instead of simply discarding it.
Another issue is that this solution contains a lot of code duplication. Apart from the range check, both do...while loops are nearly identical. Therefore, it would be better to put this loop into a function, which can be called from several places in your code.
However, I generally don't recommend that you use std::istream::operator >>, because its behavior is not always intuitive. For example, as already pointed out above:
It does not always read a whole line of input, so that you must explicitly discard the remainder of the line.
It accepts 4abc as valid input for the number 4.
In my experience, if you want proper input validation of integer input, it is usually better to write your own function that reads a whole line of input using std::getline and converts it with std::stoi. If the input is invalid, then the function should automatically reprompt the user.
In my example below, I am calling this function get_int_from_user.
If you want to additionally ensure that the input is in a certain range, then you can call the function get_int_from_user in an infinite loop, and break out of that loop once you determine that the input is valid.
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
int get_int_from_user( const std::string& prompt );
int main()
{
int nums[100];
int n;
double sum;
//repeat loop forever, until input is good
for (;;) //equivalent to while(true)
{
n = get_int_from_user( "How many numbers will you input? " );
if ( 1 <= n && n <= 100 )
//input is good
break;
std::cout << "Error! Number should in range of (1 to 100) only.\n";
}
//read one number per loop iteration
for( int i = 0; i < n; i++ )
{
std::ostringstream prompt;
prompt << "Enter number #" << i + 1 << ": ";
nums[i] = get_int_from_user( prompt.str() );
sum += nums[i];
}
std::cout << "Average: " << sum / n << '\n';
}
int get_int_from_user( const std::string& prompt )
{
std::string line;
std::size_t pos;
int i;
//repeat forever, until an explicit return statement or an
//exception is thrown
for (;;) //equivalent to while(true)
{
//prompt user for input
std::cout << prompt;
//attempt to read one line of input from user
if ( !std::getline( std::cin, line ) )
{
throw std::runtime_error( "unexpected input error!\n" );
}
//attempt to convert string to integer
try
{
i = std::stoi( line, &pos );
}
catch ( std::invalid_argument& )
{
std::cout << "Unable to convert input to number, try again!\n";
continue;
}
catch ( std::out_of_range& )
{
std::cout << "Out of range error, try again!\n";
continue;
}
//The remainder of the line is only allowed to contain
//whitespace characters. The presence of any other
//characters should cause the entire input to get rejected.
//That way, input such as "6sdfj23jlj" will get rejected,
//but input with trailing whitespace will still be accepted
//(just like input with leading whitespace is accepted by
//the function std::stoi).
for ( ; pos < line.length(); pos++ )
{
if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
{
std::cout << "Invalid character found, try again!\n";
//we cannot use "continue" here, because that would
//continue to the next iteration of the innermost
//loop, but we want to continue to the next iteration
//of the outer loop
goto continue_outer_loop;
}
}
//input is valid
return i;
continue_outer_loop:
continue;
}
}
This program has the following behavior:
How many numbers will you input? 200
Error! Number should in range of (1 to 100) only.
How many numbers will you input? -31
Error! Number should in range of (1 to 100) only.
How many numbers will you input? test
Unable to convert input to number, try again!
How many numbers will you input? 4abc
Invalid character found, try again!
How many numbers will you input? 4
Enter number #1: 1
Enter number #2: 2
Enter number #3: 3
Enter number #4: 4
Average: 2.5
As you can see, it now correctly rejects the input 4abc.
I believe that using the function get_int_from_user makes the code in main much cleaner.
Note that the code above uses one goto statement. Under most circumstances, you should avoid using goto, but for breaking out of nested loops, it is considered appropriate.
#include <iostream>
#include <limits>
using namespace std;
int avg(int sum, int n)
{
int average;
average = sum/n;
cout<<"Avg = "<<average;
}
int main()
{
int n;
cout << "how many numbers will you input?: ";
cin >> n;
int w = n;
int num[w];
int sum;
while(n>100||n<=0)
{
cout << "Error! number should in range of (1 to 100) only." << endl;
cout << "Enter the number again: ";
cin >> n;
}
for(int i = 0; i < n; ++i)
{
cout << i + 1 << "Enter number: ";
cin >> num[i];
if(!cin)
{
cout << "Wrong Choice. " << endl;
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
n++;
continue;
}
else
{
sum += num[i];
}
}
cout<<"Sum = "<<sum<<endl;
avg(sum,w);
}

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++

error: comp. bet. signed/unsigned integer expressions CODEBLOCKS

the assignment is: have a number saved in a string, then convert from a string to an integer--> convert that number to a decimal number from N-base the user inputs.
#include <iostream>
using namespace std;
int main()
{
string snum;
int n=0, base, res;
cout << "enter n: ";
cin >> snum;
cout << "enter base: ";
cin << base; //THIS IS LINE 13
for (int i=0; i<snum.length(); i++) // des order
{
int digit = snum.at(i) - '0';
n = (n*1) + digit;
if (
base <= 10
) res = base * n;
cout << "n is " << res << endl;
}
}
Im getting error: NO MATCH BETWEEN SIGNED AND UNSIGNED INTEGER EXPRESSIONS [Line 13]
ty all!!
*if u find any problems in logic please let me know!
*using codeblocks
with
cin << base; //THIS IS LINE 13
you mean
cin >> base;
EDIT:
you should convert the number differently, instead of grabbing each character take the whole string and convert it to a number. You can use a stream for that or just atoi( sum.c_str() ) to get the integer number.
thereafter convert the value to whatever base you want.
e.g.
snum=12 (converted to integer from input string)
base=8
12 - 8 (>8, number of times you can subtract) --> 1
4 - 8 (<8 use remainder) --> 4
output == 14

Using C isdigit for error checking

While using the boolean check for the int num this loop doesn't work. The lines after it go unrecognized. Enter and integer like 60 and it just closes. Did I use isdigit wrong?
int main()
{
int num;
int loop = -1;
while (loop ==-1)
{
cin >> num;
int ctemp = (num-32) * 5 / 9;
int ftemp = num*9/5 + 32;
if (!isdigit(num)) {
exit(0); // if user enters decimals or letters program closes
}
cout << num << "°F = " << ctemp << "°C" << endl;
cout << num << "°C = " << ftemp << "°F" << endl;
if (num == 1) {
cout << "this is a seperate condition";
} else {
continue; //must not end loop
}
loop = -1;
}
return 0;
}
When you call isdigit(num), the num must have the ASCII value of a character (0..255 or EOF).
If it's defined as int num then cin >> num will put the integer value of the number in it, not the ASCII value of the letter.
For example:
int num;
char c;
cin >> num; // input is "0"
cin >> c; // input is "0"
then isdigit(num) is false (because at place 0 of ASCII is not a digit), but isdigit(c) is true (because at place 30 of ASCII there's a digit '0').
isdigit only checks if the specified character is a digit. One character, not two, and not an integer, as num appears to be defined as. You should remove that check entirely since cin already handles the validation for you.
http://www.cplusplus.com/reference/clibrary/cctype/isdigit/
If you're trying to protect yourself from invalid input (outside a range, non-numbers, etc), there are several gotchas to worry about:
// user types "foo" and then "bar" when prompted for input
int num;
std::cin >> num; // nothing is extracted from cin, because "foo" is not a number
std::string str;
std::cint >> str; // extracts "foo" -- not "bar", (the previous extraction failed)
More detail here:
Ignore user input outside of what's to be chosen from

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. :)