I'm doing a problem on HR and cant figure out how to check for error without using conditional statements. How is this done in C++?
// if string is int output it, else output "Bad string"
// need to do this without any loops/conditionals
int main(){
string S;
char *end;
long x;
cin >> S;
const char *cstr = S.c_str();
x = strtol(cstr,&end,10);
if (*end == '\0')
cout << x;
else
cout << "Bad string";
return 0;
}
Should I be using something besides strtol?
stoi is indeed what you'll want to use.
Given an input in string S one possible way to handle it would be:
try {
cout << stoi(S) << " is a number\n";
} catch(const invalid_argument& /*e*/) {
cout << S << " is not a number\n";
}
Live Example
The violation here is that stoi is only required to cosume the leading numeric part of the string not ensure that the entire string is an int. So "t3st" will fail cause it's not led by a number, but "7est" will succeed returning a 7. There are a handful of ways to ensure that the entire string is consumed, but they all require an if-check.
One way would be:
char const *m[2] = { "Bad string", S.c_str() };
cout << m[*end == '\0'];
Related
I'm new to statically typed C++. In JavaScript, I could just check the data type first, but that seems to be very complicated, and the answers all seem to imply that you aren't "getting" the language.
here's the code I was testing out rand() with, where I came upon the issue of converting strings to integers:
int main(){
std::string input;
cout <<endl<< "What to do?"<<endl;
cin >> input;
if (input == "rand")
{
cout << "what is the max?" << endl;
cin >> input;
int number;
if (stoi(input) > 1) {
number = stoi(input);
}
else {
number = 10;
cout << "using 10"<<endl;
}
cout << rand() % stoi(input);
return main();
}
}
so in Javascript, I would just check the type of input or result, but what do people do in C++?
Not allowed to say thank you in the comments so I'm saying thank you here!
Well, let's try out what happens: https://godbolt.org/z/1zahbW
As you can see, std::stoi throws an exception if you pass it invalid input or its input is out of range.
You should, however, be aware that std::cin >> some_string; is somewhat non-obvious in that it reads in the first "word", not a line or anything like that, and that std::stoi does the same thing (again).
One way to perform the check, could be like this:
#include <string>
#include <iostream>
int main(){
std::cout << "Please give me a number: " << std::flush;
std::string input;
std::getline(std::cin, input);
try {
auto value = std::stoi(input);
std::cout << "Thanks for the " << value << " (but the string was \"" << input << "\")\n";
} catch(std::invalid_argument const&) {
std::cout << "The provided value is not an integer\n";
} catch(std::out_of_range const&) {
std::cout << "The provided value is out of range\n";
}
}
https://godbolt.org/z/rKrv8G
Note that this will parse " 42 xyz" as 42. If that is a problem for your use case, you may wish to use std::strtoi directly, or to check if your input is valid before parsing (e.g., using a regex)
Regarding to the documentation of std::stoi it throws an std::invalid_argument.
What you could do is to place your std::stoi call inside a try and then catch the std::invalid_argument, but personally i wouldn't do that.
Instead, it is (most likely) a lot better to check if the first character of your input is an int, because if it is one, it can simply be parsed by std::stoi.
You can do that by e.g. doing the following:
int max = 0;
std::string input;
std::cin >> input;
if(std::isdigit(input[0]))
max = std::stoi(input);
EDIT: Please note that this would not respect the case of a too big number, to handle that case you would need an additional check.
I am wrote a function that can replace cin for integers and potentially doubles, that includes error checking capabilities. Using cin.fail() I was able to check for most cases, but that didn't cover the case where the input was followed by a string without a space. For example, "23tewnty-three." The following code accommodates this.
int getUserInt(string prompt = "Enter an integer: ", string errorMessage "Error: Invalid Input") {
const int IGNORE_MAX = 100;
int userInt = 0;
bool isContinue = true;
do {
// initialize and reset variables
string inputStr;
istringstream inputCheck;
userInt = 0;
// get input
cout << prompt;
cin >> inputStr;
inputCheck.str(inputStr);
// check for valid input
inputCheck >> userInt;
if (!inputCheck.fail()) {
// check for remaining characters
if (inputCheck.eof()) { // Edit: This is the section that I tried replacing with different code (made code compilable in response to comment)
isContinue = false;
}
else {
cout << errorMessage << endl;
}
}
else {
// reset cin and print error message
cin.ignore(IGNORE_MAX, '\n');
cin.clear();
cout << errorMessage << endl;
}
} while (isContinue);
return userInt;
}
This code works, but the reason I am posting this to Stack Overflow instead of Code Review is because my main question is about why some of code didn't work as I expected. The following is what I tried in place of inputCheck.eof() in the previous code. My questions are what are the differences between the following code? Why didn't methods 2) and 3) work? and which method is preferred?
inputCheck.eof()
inputCheck.peek() == EOF
inputCheck.str().empty()
inputCheck.rdbuf()->in_avail() == 0
1) and 4) worked as expected, but 2) and 3) did not.
Edit:
I believe 3) didn't work as expected because inputCheck.str() returns what was contained in inputStr when inputCheck.str(inputStr) was called. However, I have no idea why inputCheck.peek() == EOF didn't work.
If this is relevant information, I am compiling and running on windows through bash g++.
For every prompt you provide, you can expect your user to press Enter. Obtain input as a string, then try to convert. (Don’t try to convert from cin.)
Bonus: here’s a function to perform conversion.
template <typename T>
auto string_to( const std::string & s )
{
T value;
std::istringstream ss( s );
return ((ss >> value) and (ss >> std::ws).eof())
? value
: std::optional<T> { };
}
You’ll need C++17 for that, or to #include <boost/optional.hpp> instead.
Now:
std::cout << "Enter an integer! ";
std::string s;
getline( std::cin, s );
auto x = string_to <int> ( s );
if (!x)
{
std::cout << "That was _not_ an integer.\n";
}
else
{
std::cout << "Good job. You entered the integer " << *x << ".\n";
}
No more worrying about clearing or resetting cin. Handily perform some loops (such as allow user three attempts before quitting). Et cetera.
I was typing this and it asks the user to input two integers which will then become variables. From there it will carry out simple operations.
How do I get the computer to check if what is entered is an integer or not? And if not, ask the user to type an integer in. For example: if someone inputs "a" instead of 2, then it will tell them to reenter a number.
Thanks
#include <iostream>
using namespace std;
int main ()
{
int firstvariable;
int secondvariable;
float float1;
float float2;
cout << "Please enter two integers and then press Enter:" << endl;
cin >> firstvariable;
cin >> secondvariable;
cout << "Time for some simple mathematical operations:\n" << endl;
cout << "The sum:\n " << firstvariable << "+" << secondvariable
<<"="<< firstvariable + secondvariable << "\n " << endl;
}
You can check like this:
int x;
cin >> x;
if (cin.fail()) {
//Not an int.
}
Furthermore, you can continue to get input until you get an int via:
#include <iostream>
int main() {
int x;
std::cin >> x;
while(std::cin.fail()) {
std::cout << "Error" << std::endl;
std::cin.clear();
std::cin.ignore(256,'\n');
std::cin >> x;
}
std::cout << x << std::endl;
return 0;
}
EDIT: To address the comment below regarding input like 10abc, one could modify the loop to accept a string as an input. Then check the string for any character not a number and handle that situation accordingly. One needs not clear/ignore the input stream in that situation. Verifying the string is just numbers, convert the string back to an integer. I mean, this was just off the cuff. There might be a better way. This won't work if you're accepting floats/doubles (would have to add '.' in the search string).
#include <iostream>
#include <string>
int main() {
std::string theInput;
int inputAsInt;
std::getline(std::cin, theInput);
while(std::cin.fail() || std::cin.eof() || theInput.find_first_not_of("0123456789") != std::string::npos) {
std::cout << "Error" << std::endl;
if( theInput.find_first_not_of("0123456789") == std::string::npos) {
std::cin.clear();
std::cin.ignore(256,'\n');
}
std::getline(std::cin, theInput);
}
std::string::size_type st;
inputAsInt = std::stoi(theInput,&st);
std::cout << inputAsInt << std::endl;
return 0;
}
Heh, this is an old question that could use a better answer.
User input should be obtained as a string and then attempt-converted to the data type you desire. Conveniently, this also allows you to answer questions like “what type of data is my input?”
Here is a function I use a lot. Other options exist, such as in Boost, but the basic premise is the same: attempt to perform the string→type conversion and observe the success or failure:
template <typename T>
auto string_to( const std::string & s )
{
T value;
std::istringstream ss( s );
return ((ss >> value) and (ss >> std::ws).eof()) // attempt the conversion
? value // success
: std::optional<T> { }; // failure
}
Using the optional type is just one way. You could also throw an exception or return a default value on failure. Whatever works for your situation.
Here is an example of using it:
int n;
std::cout << "n? ";
{
std::string s;
getline( std::cin, s );
auto x = string_to <int> ( s );
if (!x) return complain();
n = *x;
}
std::cout << "Multiply that by seven to get " << (7 * n) << ".\n";
limitations and type identification
In order for this to work, of course, there must exist a method to unambiguously extract your data type from a stream. This is the natural order of things in C++ — that is, business as usual. So no surprises here.
The next caveat is that some types subsume others. For example, if you are trying to distinguish between int and double, check for int first, since anything that converts to an int is also a double.
There is a function in c called isdigit(). That will suit you just fine. Example:
int var1 = 'h';
int var2 = '2';
if( isdigit(var1) )
{
printf("var1 = |%c| is a digit\n", var1 );
}
else
{
printf("var1 = |%c| is not a digit\n", var1 );
}
if( isdigit(var2) )
{
printf("var2 = |%c| is a digit\n", var2 );
}
else
{
printf("var2 = |%c| is not a digit\n", var2 );
}
From here
If istream fails to insert, it will set the fail bit.
int i = 0;
std::cin >> i; // type a and press enter
if (std::cin.fail())
{
std::cout << "I failed, try again ..." << std::endl
std::cin.clear(); // reset the failed state
}
You can set this up in a do-while loop to get the correct type (int in this case) propertly inserted.
For more information: http://augustcouncil.com/~tgibson/tutorial/iotips.html#directly
You can use the variables name itself to check if a value is an integer.
for example:
#include <iostream>
using namespace std;
int main (){
int firstvariable;
int secondvariable;
float float1;
float float2;
cout << "Please enter two integers and then press Enter:" << endl;
cin >> firstvariable;
cin >> secondvariable;
if(firstvariable && secondvariable){
cout << "Time for some simple mathematical operations:\n" << endl;
cout << "The sum:\n " << firstvariable << "+" << secondvariable
<<"="<< firstvariable + secondvariable << "\n " << endl;
}else{
cout << "\n[ERROR\tINVALID INPUT]\n";
return 1;
}
return 0;
}
I prefer to use <limits> to check for an int until it is passed.
#include <iostream>
#include <limits> //std::numeric_limits
using std::cout, std::endl, std::cin;
int main() {
int num;
while(!(cin >> num)){ //check the Input format for integer the right way
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
cout << "Invalid input. Reenter the number: ";
};
cout << "output= " << num << endl;
return 0;
}
Under C++11 and later, I have the found the std::stoi function very useful for this task. stoi throws an invalid_argument exception if conversion cannot be performed. This can be caught and handled as shown in the demo function 'getIntegerValue' below.
The stoi function has a second parameter 'idx' that indicates the position of the first character in the string after the number. We can use the value in idx to check against the string length and ascertain if there are any characters in the input other than the number. This helps eliminate input like 10abc or a decimal value.
The only case where this approach fails is when there is trailing white space after the number in the input, that is, the user enters a lot of spaces after inputting the number. To handle such a case, you could rtrim the input string as described in this post.
#include <iostream>
#include <string>
bool getIntegerValue(int &value);
int main(){
int value{};
bool valid{};
while(!valid){
std::cout << "Enter integer value: ";
valid = getIntegerValue(value);
if (!valid)
std::cout << "Invalid integer value! Please try again.\n" << std::endl;
}
std::cout << "You entered: " << value << std::endl;
return 0;
}
// Returns true if integer is read from standard input
bool getIntegerValue(int &value){
bool isInputValid{};
int valueFromString{};
size_t index{};
std::string userInput;
std::getline(std::cin, userInput);
try {
//stoi throws an invalid_argument exception if userInput cannot be
//converted to an integer.
valueFromString = std::stoi(userInput, &index);
//index being different than length of string implies additional
//characters in input that could not be converted to an integer.
//This is to handle inputs like 10str or decimal values like 10.12
if(index == userInput.length()) isInputValid = true;
}
catch (const std::invalid_argument &arg) {
; //you could show an invalid argument message here.
}
if (isInputValid) value = valueFromString;
return isInputValid;
}
You could use :
int a = 12;
if (a>0 || a<0){
cout << "Your text"<<endl;
}
I'm pretty sure it works.
I've looked everywhere, but I cannot find a solution to exactly why this happens in my situation.
I'm making a simple string function that asks for a string, and prints out the length.
However, I get an "Invalid Null Pointer" assertion error when I run the compiled version. I have had no errors when compiling, but the error comes up when I run it.
This is the function causing the problem:
string getString()
{
string wordInput;
cout << "Enter a word that has AT LEAST four (4) letters! ";
getline(cin, wordInput);
while (wordInput.length() <= 3)
{
cout << "Enter a word that has AT LEAST four (4) letters! ";
getline(cin, wordInput);
}
return 0;
}
The while loop isn't a problem. I commented it out and I still got the same error. How is initializing word input, cout, and getline giving me the error?
Here is my whole code so far (not finished). I tried running the string by itself too, the getKeyLetter function isn't a problem.
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
char getKeyLetter()
{
char keyLetter;
string convertFromString;
cout << "Enter a SINGLE character! ";
getline(cin, convertFromString);
while (convertFromString.length() > 1)
{
cout << "Enter a SINGLE character! ";
getline(cin, convertFromString);
}
assert(convertFromString.size() == 1);
keyLetter = convertFromString[0];
return 0;
}
string getString()
{
string wordInput;
cout << "Enter a word that has AT LEAST four (4) letters! ";
getline(cin, wordInput);
while (wordInput.length() <= 3)
{
cout << "Enter a word that has AT LEAST four (4) letters! ";
getline(cin, wordInput);
}
return 0;
}
int main()
{
getKeyLetter();
getString();
return 0;
}
First, in your GetKeyChar() function, writing:
char ch;
cout << "Enter a single character: ";
cin >> ch;
will give you the first character the person types into the command prompt. So, typing "check" will have ch = c.
Second, as eran said, at the end of your functions, you have
return 0;
Unless you want both functions to return a char and string respectively, make them void GetKeyLetter() and void GetString(). Or, if you do want to return something, have them return ch (from my example) and return wordInput.
Only int main(), per standard, needs return 0, to show you that it exited correctly. the variable type you put in front of your functions is what variable you plan on returning. 0 is an int, so that's what it returns based on convention. As was pointed out, a return is not necessary in main. If you want your functions to return values, do this in your main.
string str;
char ch;
ch = GetKeyLetter();
str = GetString();
return 0;
And have your functions return the char and string value you want them to.
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);