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. :)
Related
I am struggling to create a loop for getting input from user. The input must push_back() each instance.
#include <iostream>
#include <array>
#include <cstring>
#include <vector>
#include <string>
#include <string.h>
using namespace std;
int main()
{
vector <string> bookQ = { "what","book","is","that","you","are","reading" };
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
string input;
int x = 0;
for (x != '1') { // require a loop to input string and end when user prompts
cout << "Enter 1 to stop" << endl; //
cin >> x; //
getline(cin, input); //
bookQ.push_back(input); //
} //
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}
Your for loop is missing the declaration and (iteration) expression parts:
for (declaration-or-expression; declaration-or-expression; expression)
so it should have looked like this:
for (;x != '1';) {
which is generally written as
while (x != '1') {
That would cause problems though since it would not stop directly when the user entered 1.
You are also comparing an int with a char ('1'), so in order to exit the loop, the user would have had to enter 49 (the ASCII value for 1), not 1.
You are also mixing formatted input (cin >> x) with unformatted input (getline). I suggest that you stick to one only.
Example:
while(cout << "Enter 1 to stop\n", getline(cin, input) && input != "1") {
bookQ.push_back(input);
}
Assuming you meant that input is a string, then you've made a few mistakes with types. First of all, you've used wrong type for variable x, you used int which is integer type, and the type string is required. Secondly, when comparing x with '1' you used single quotes, which define the type of variable as char, not string. To make 1 a string you should use double quotes, like so "1". Besides that, you have used for(condition), which is incorrect syntax. You should use while(condition). Also, when your loop iterates, the x variable is the input book name, and input variable is always an empty string, so I would suggest replace input with x everywhere. The working code is below.
P.S. I am not sure whether you want "1" to be in the final vector, so I haven't changed that
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<string> bookQ = {"what", "book", "is", "that", "you", "are", "reading"};
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
string input;
string x;
while (x != "1") {
cout << "Enter 1 to stop" << endl;
cin >> x;
bookQ.push_back(x);
}
for (int i = 0; i < bookQ.size(); i++) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}
simply check if input is 1 everytime the user enters somthing, and when it does = 1, simply break loop.
string x;
while (true) { // require a loop to input string and end when user prompts
cout << "Enter 1 to stop" << endl;
cin >> x;
if (x == "1"){
break;
}
getline(cin, x);
bookQ.push_back(x);
}
}
First, your for syntax is wrong. You want a while loop instead, or in this case a do..while loop would make more sense. Also, you are pushing the user's input into the vector before validating what the input actually is.
Second, x is an integer, but '1' is a character whose ASCII value is number 49. Your loop will never end, because != will always be true. Since you want the user to enter number 1 to stop the loop, you need to drop the quotes:
Third, what is the point of pre-populating bookQ? Just declare the bookQ without any initial data, and then cout the entire question as a normal string. This way, after the user is done entering input, the vector will contain only the user's input and nothing else.
Try something more like this:
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
using namespace std;
int main()
{
vector <string> bookQ;
string input;
cout << "what book is that you are reading" << endl;
do {
cout << "Enter a book, or 1 to stop" << endl;
getline(cin >> ws, input);
if (input == "1") break;
bookQ.push_back(input);
}
while (true);
for (size_t i = 0; i < bookQ.size(); ++i) {
cout << bookQ[i] << ' ';
}
cout << endl;
return 0;
}
I have looked in several places on the Internet but cannot find what I am looking for. Basically I am trying to understand data validation and filter out all user input except either the number 1 or 2. I have found information for validating ints. Found stuff on filtering out chars and strings. But when I try to put them together it doesn't work. Basically if the user enters something that is not 1 or 2, it does not end a loop asking for correct input.
I have included more details in the comments in the code below.
Any help is appreciated!
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter 1 or 2. No other numbers or characters."
<< std::endl;
std::string numberString;
//Used a string so if the user enters a char it gets converted to an
//integer value of 0.
getline(std::cin, numberString);
int numberInteger = atoi(numberString.c_str());
//If the user enters the wrong number, char, or string,
//the program goes to this area of code.
//But if a subsequent correct entry is made, the loop does not end.
if (numberInteger < 1 || numberInteger > 2)
{
do
{
//Tried using these two lines of code to clear the input buffer,
//but it doesn't seem to work either:
//std::cin.clear();
//std::cin.ignore(std::numeric_limits <std::streamsize>::max(), '\n');
std::cout << "Invalid input. Please enter 1 or 2. No other numbers or characters."
<< std::endl;
getline(std::cin, numberString);
int numberInteger = atoi(numberString.c_str());
} while (numberInteger < 1 || numberInteger > 2);
}
else
{
std::cout << "You entered either 1 or 2. Great job! "
<< std::endl;
}
return 0;
}
#include <cctype>
#include <limits>
#include <iostream>
std::istream& eat_whitespace(std::istream& is)
{
int ch;
while ((ch = is.peek()) != EOF && ch != '\n' &&
std::isspace(static_cast<char unsigned>(ch))) // 0)
is.get(); // As long as the next character
// is a space, get and discard it.
return is;
}
int main()
{
int choice;
while (std::cout << "Please enter 1 or 2. No other numbers or characters: ",
!(std::cin >> std::skipws >> choice >> eat_whitespace) || // 1)
std::cin.peek() != '\n' || // 2)
choice < 1 || 2 < choice) { // 3)
std::cerr << "I said 1 or 2 ... nothing else ... grrr!\n\n";
std::cin.clear(); // 4)
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 5)
}
std::cout << "Input was " << choice << '\n';
}
0) Don't feed isspace() negative values.
1) Extraction of an int failed. Allow whitespace before and after the int.
2) If the next character in the stream is not a newline character, there is garbage left eat_whitespace() didn't swallow --> complain.
3) choice not in range.
4) clear flags to make sure input functions will work again.
5) ignore up to maximum streamsize characters untill the next newline.
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;
}
So recently, I came across using isdigit as a way to check to see if an entered value for an int is actually an integer, rather than a string or a char.
However, when I wrote a short program to play around with that, the program failed to execute from that point on.
EDIT: I also in the program wanted to take the invalid data and convert it to a different data type.
Here is the code:
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
int enterCFN;
char revisit;
int review(0);
cout << "Enter a digit: ";
cin >> enterCFN;
bool y = isdigit(enterCFN);
if (y == false)
{
// This is the data conversion section
revisit = enterCFN;
revisit = review;
cout << review << "\n";
}
else
{
cout << enterCFN << "\n";
}
return 0;
}
Is there anyone who can correct my error and show me what I'm doing wrong?
enterCFN is an int. It stores a number. isdigit() checks if a character represents a number. These are not the same thing: for example 32 is a number but char(32) means ' ' (space).
What you want instead is this:
if (cin >> enterCFN)
That will take the input from the user and check if it is valid all at once. No need for isdigit().
isdigit() checks if a given character is one of 0-9
For validating integer do something like following:
std::cout << "Enter a digit: ";
std::cin >> enterCFN ;
while (1)
{ if ( std::cin >> enterCFN )
{
// good input
break ;
}
else
{
std::cout << "Enter a digit: ";
// clear stream flags set due to bad input
std::cin.clear();
// get rid of the bad input.
// ignore the rest of the line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
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
}