I'm trying to write in C++ a function (leggiInteroEstrIncl) that prompts the user to type by keyboard an integer number included in a given range (between minimo and massimo).
Following is the function I wrote and then a statement, in the main(), to invoke it:
#include <iostream>
using namespace std;
int leggiInteroEstrIncl(string stringaDaStampare, int minimo, int massimo) {
int numInserito = 0;
bool errore = false;
do {
errore = false;
cout << stringaDaStampare << " (un numero intero compreso tra " << minimo
<< " e " << massimo << " estremi inclusi): ";
try {
cin >> numInserito;
} catch (...) {
errore = true;
cout << "Hai inserito un numero non valido, prova ancora" << endl;
}
if (errore == false && (numInserito < minimo || numInserito > massimo)) {
errore = true;
cout << "Hai inserito un numero al di fuori dell'intervallo richiesto: "
<< minimo << " <-> " << massimo << endl;
}
} while (errore);
return numInserito;
}
int main() {
int number = 0;
number = leggiInteroEstrIncl(
"Inserire la cifra in Yen da ripartire in banconote e monete", 1, 30000);
system("pause");
return 0;
}
If I type a valid integer number which is not included in the specified range, this piece of software works and asks the user to type again, but if I type something which is not a number, for example the word "hello", this software goes in a sort of loop and doesn't stop to ask the user to type again.
Could you please tell me what is wrong with it?
Thank you
You can use std::string to get input:
string insertio;
cin >> inserito;
and then use one of this function:
http://en.cppreference.com/w/cpp/string/basic_string/stol
which throws proper exception if there isn't a number in string.
If you need to check more solutions, check this one:
How to determine if a string is a number with C++?
This
cin >> numInserito;
attempts to read in a number and nothing else.
It will succeed with a number, as you have observed.
With a non-number it will fail, but not in a way to trigger the catch part.
It will instead just not read anything in and especially it will leave the non-number in the input stream.
If you then continue trying to read in a number, it will continue failing.
When reading in a number fails you need to read in whatever there is and probably ignore it.
In order to ignore the non-number, read it in as a string and do nothing with it
(as described in the answer by BartekPL):
string insertio;
cin >> inserito;
Related
So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if(isdigit(guess))
{
game.guess(guess);
else
{
std::cout << "Error\n"; //this would be looped endlessly
}
}
std::cout << "You got " << game.getCorrect() << " correct" << std::endl;
return 0;
}
NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.
The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.
Use something like the following
int getIntInput() {
try {
std::string input;
std::cout << "\nPlease Enter a valid Integer:\t";
std::cin >> input;
size_t takenChars;
int num = std::stoi(input, &takenChars);
if (takenChars == input.size()) return num;
} catch (...) {}
return getIntInput();
}
Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.
Solution:
Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.
The solution implemented in my code looks like this:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if (std::cin.fail())
{
std::cout << "Please enter a valid number\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
game.guess(guess);
}
Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)
In my programming class, we have the following problem :
The user inputs an integer number. The program must make the sum of that number
and that number reversed. In other words, let's say the user input 1920. Here's what the program must do :
1920+0291=2211
Here's the code I came up with :
int main()
{
cout << "Entrer votre number entier" << endl;
int number;
cin >> number;
string numberInverse = to_string(number);
string numberComparatoire = numberInverse;
for (unsigned compteur = 0; compteur <= numberInverse.length(); compteur++){
numberInverse[compteur] = numberComparatoire[numberComparatoire.length() - compteur];
}
int numberInverseInt = stoi(numberInverse);
int somme = number + numberInverseInt;
cout << "Le number inversé est " << numberInverse << " et " << number << "+" << numberInverseInt << "=" << somme << endl;
return 0;
}
The names of the of the variables and the outputs are in french but that's not important.
I can build the solution to my code but upon running it, let's say I input 1920, my program shows mw an error message saying it had to abort and I don't understand why. Please help :( I know this is probably a bit of a beginner question in programming so guide me in my learnings.
Thank you very much!
I want to create a program that when a user inputs something that I didn't define, the program prompts him again.
I did it with if statements but it only loops for 1 time and doesn't do it again. I tried loops but whenever the input is false it just breaks the condition and refuses all inputs alike. In c++.
Any help is much appreciated.
#include <iostream>
#include <string>
using namespace std;
void xD(){string x;
do{cout << "Retry\n";
cin >> x;}while(true);}
//declaring a function to make the shop
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
// if u chose bow you get this and get to choose again
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;}
/*now the problem that whenever I excute the code and type something other than bow it gives me the cin only once more and then fails even if I type bow in the 2nd attempt*/
//in my desperate 5k attempt, I tried creating a function for it.. no use.
//i want it o keep prompting me for input till i type "bow" and the other block excutes. but it never happens.
else{xD();}
}
int main(){
string name;
string i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if(i == "shop"){shop();}
else{cin >> i;}
return 0;
}
The problem lies on the condition in this loop block
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(true);
}
The while(true) condition makes it loops forever regardless of the input. To fix this, you can change the condition:
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(x!="bow");
cout << "you bought the bow. and some other messages"<<endl;
}
That should work. However, it is still too complicated for me. This can be simplified into the snippet below:
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
while (x!="bow"){
cout << "Retry\n";
cin>>x;
}
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;
}
Instead of doing this approach (which is checking the condition only once):
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << "
coins." << endl; cin >> x;
} else{
xD();
}
which is actually a RECURSIVE invocation to the method xD()
you should do a do-while loop,
example:
while (x.compare("bow") != 0)
{
cout << "sorry, wrong input, try again...";
cin >> x;
}
note the use of the compare method instead of the == operator
here more about it in the documentation
You can use return value of cin >> [your input object] here to check status or istream's method fail(). As soon as input stream fails to parse whole or part of streams it fails and stay in state of failure until you clear it. Unparsed input is preserved (so you can try to parse it differently?)m so if you try to >> again to object of same type, you'll get same failure. To ignore N chars of imput, there is method
istream::ignore(streamsize amount, int delim = EOF)
Example:
int getInt()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter an int value: ";
long long x; // if we'll use char, cin would assume it is character
// other integral types are fine
std::cin >> x;
// if (! (std::cin >> x))
if (std::cin.fail()) // has a previous extraction failed?
{
// yep, so let's handle the failure, or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
}
// Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
else if(( x > std::numeric_limits<int>::max()) ||
( x < std::numeric_limits<int>::min()))
{
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return x;
}
}
For strings parsing is almost always successful but you'll need some mechanism of comparison of string you have and one that is allowed. Try look for use of std::find() and some container that would contain allowed options, e.g. in form of pair<int,string>, and use int index in switch() statement (or use find_if and switch() within the function you give to it).
Consider that if() statement is a one_direction road, it checks the condition and if the condition was satisfied it goes to its bracket and do blah blah blah , if there is any problem with condition compiler passes ifand jump to compile other codes.
Every time that you begin to compile the codes it begins from int main() function. You did the wrong thing in the if and else statements again
Here is the correct code .I did the necessary changes.
#include "stdafx.h"
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
#define coins 500 ;
#define bow_cost 200 ;
int shop(string x)
{
//There is no need to allocate extra memory for 500 and 200 while they are constant.``
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
do
{
cout << "Input another :\n";
cin >> x;
if (x == "bow")
{
return (coins - bow_cost); //return to function as integer
}
} while (true);
}
int main()
{
string name, i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if (i == "shop")
{
cout << "Input :\n";
cin >> name;
cout << shop(name) << "you bought the bow.\n you now have " << " coins." << "\n";
}
//argument passed to shop funnction parameters.
system("pause");
return 0;
}
This question already has answers here:
Why can't the switch statement be applied to strings?
(22 answers)
Closed 3 years ago.
I'm working on a small project on Dev-C++. I'm trying to make a bot to ask you some questions, but I can't use the switch statetments with the strings. Every time I try to do so it shows error! I also tried to change the srings to normal int variables but when I the code runs all at once after answering the first question! Does anyone knows how to fix any of these situations?
Here is my code:
// #include "stdafx";
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
using namespace std;
int main()
{
string comida;
string nome;
string idade;
string pais;
cout << "Ola, o meu nome e Aleksandar. Qual e o teu nome?" << endl; //Ask for nome
cin >> nome; //Recieve variable nome
cout << "Es de que pais, " << nome << "?" << endl; //Ask for pais
cin >> pais; //Receive pais
cout << pais << " e um pais bonito. " << "Eu sou de Portugal!" << endl;
cout << "Quantos anos tens " << nome << "?" << endl; //Ask for idade
cin >> idade; //Receive variable idade
switch (idade) {
case 21:
cout << "O meu irmao tambem tem 21 anos!" << endl;
break;
}
cout << "Eu tenho 28" << endl;
cout << "Qual e a tua comida preferida?" << endl; //Ask for comida
cin >> comida; //Receive variable comida
cout << "Tambem gosto muito de " << comida << ". Mas gosto mesmo e de Vatruchka!" << endl;
cout << "Xau " << nome << "!" << endl;
}
If the string contains a number, switch(std::stoi(idade)) will work. But that doesn't work if idade contains something else.
A switch will not compile when non-intergal (i.e. string, float, bool, vector, etc...) data-types are assigned to the switch's case: statements. Furthermore, its necessary that the values assigned to the case: statements are const.
In other words:
Switches must use "constant integral data-types" (i.e. 'enum', 'int', 'char', etc...), and cannot implament strings as conditional statements, however; that is not the same as saying that strings cannot be used in a conditional statement, they very much can be & often are — see the example below:
std::string s;
std::cin >> s;
if (s == "Yes")
{
std::cout << "You said yes!" << std::endl;
}
else if (s == "No")
{
std::cout << "You said no?" << std::endl;
}
else
{
std::cout << "You said something I don't understand" << std::endl;
}
So to finish this answer, you can see that you can achieve the same thing you could with a switch statement using if/else blocks. It may, or it may not, be ideal for your situation, but this is how C++, and switch statements work, so your stuck with it — like it, or not...
You can't use strings — switch only works for integral case types (i.e. integers and enums).
You could use something like this, instead:
if (idade == "21") { cout << "...\n"; }
else if (idade == "something else") { cout << "...\n"; }
You describe that the code runs all at once when you change to using integers. It's possible you're forgetting to include break in each case clause.
If you have a set of different strings that you are expecting then you can set up an enum and a map (I use the word map loosely here - I don't mean the actual map in C++, although I know it is possible to do something similar with it)
Use this to turn the input into an enum and then you can run a switch on the enum
E.g.
enum class ANSWER
{
ANSWER_1,
ANSWER_2
};
class AnswerMap \\set up this class like a singleton
{
std::vector<std::pair<std::string, ANSWER>> _answer_map = {
std::make_pair("Answer 1 string", ANSWER::ANSWER_1),
std::make_pair("Answer 2 string", ANSWER::ANSWER_2)
}
std::string String(ANSWER answer); \\have this function loop through this->_answer_map until finding the pair with the second item as the given enum and return the corresponding string
ANSWER Enum(std::string answer); \\have this function do the same as this->String but find the pair where the string matches and then return the corresponding enum
}
I'm writing a program that acts as a calculator; based on the character input by the user it performs a certain operation. The structure of the program seems to work fine, but I'd like to be able to check for erroneous input. After receiving the float variable, is there any way to check if it does not contain any characters other than digits and decimals? I've tried isdigit, and this:
if (!(cin >> x)) {
cout << "You did not enter a correct number!" << endl;
return;
}
But nothing seems to be working.
Here is a sample of one of the simple operation functions I'm using:
void Add(){
float x = 0, y = 0, z = 0;
cout << "Please enter two numbers you wish "
<< "to add separated by a white space:" << endl;
cin >> x >> y;
z = x+y;
cout << x << " + " << y << " = " << z << "." << endl;
return;
}
You test the state of the stream:
float x, y;
if (std::cin >> x >> y) {
// input extraction succeeded
}
else {
// input extraction failed
}
If this isn't working for you, then you need to post the exact code that isn't working.
To detect erroneous string input where you expected a number, C++ doesn't automatically know what you want, so one solution is to first accept your input as strings, validate those strings, then if valid, only then convert the strings to float numbers using the atof() function.
The standard string class has a function called find_first_not_of() to help you tell C++ which characters you consider valid. If the function finds a character not in your list, it will return the position of the bad character, otherwise string::npos is returned.
// add.cpp
#include <iostream>
#include <string>
#include <cstdlib> // for atof()
using namespace std;
void Add()
{
cout << "Please enter two numbers you wish "
<< "to add, separated by a white space:"
<< endl;
string num1, num2;
cin >> num1;
if( num1.find_first_not_of("1234567890.-") != string::npos )
{
cout << "invalid number: " << num1 << endl;
return;
}
cin >> num2;
if( num2.find_first_not_of("1234567890.-") != string::npos )
{
cout << "invalid number: " << num2 << endl;
return;
}
float x = 0, y = 0, z = 0;
x = atof( num1.c_str() );
y = atof( num2.c_str() );
z = x+y;
cout << x << " + " << y << " = " << z << "." << endl;
}
int main(void)
{
Add();
return 0;
}
One possibility would be to read the input as a string, then use boost lexical_cast to convert to floating point. lexical_cast only considers the conversion successful if the entire input converts to the target -- otherwise, it'll throw a bad_lexical_cast exception.
Another idea would be to test the input against a regex. An example regex for a float could be
-?[0-9]+([.][0-9]+)?
This method would also make it easier to refine the matching mechanism by only modifying the regex, and you could map multiple regular expressions against different types of input, for example an integer could then be expressed as
-?[0-9]+
and so on. Keep in mind however, that this only tests if the input is a valid format, it still requires a numerical conversion afterwards (I prefer boost::lexical_cast).
(You can also try it out with http://gskinner.com/RegExr/)