Input accepting char when it should be string? - c++

I am new to C++ and am making a simple text RPG, anyway, The scenario is I have a "welcome" screen with choices 1-3, and have a simple IF statement to check them, here:
int choice;
std::cout << "--> ";
std::cin >> choice;
if(choice == 1) {
//..
That works fine, but if someone enters a letter as selection (instead of 1, 2 or 3) it'll become "-392493492"or something and crash the program. So I came up with:
char choice;
std::cout << "--> ";
std::cin >> choice;
if(choice == 1) {
//..
This works kinda fine, but when I enter a number it seems to skip the IF statements completely.. Is the char "1" the same as the number 1?
I get a compiler error with this (ISO-CPP or something):
if(choice == "1")
So how on earth do I see if they entered 1-3 correctly!?

1 is an int
'1' is a char
"1" is a char array
I guess you want to compare with '1'.

Choice doesn't become "-392493492" or something, it starts as that value (you didn't initialise it, so the initial value is unspecified) and is never set to anything else because the >> fails. You should check that such operators succeed, which is quite easy to do:
if (std::cin >> choice) {
switch (choice) {
case 1: // ...
case 2: // ...
case 2: // ...
default: // report error
}
}

Unfortunately 1 and '1' are not the same.
Look up your favorite ASCII table to know the integer value that represents the character "1" and you'll see it for yourself: '1' is mapped to 49.
There is another issue with this code "" denotes a C-string (const char*) whereas '' denotes a single character.
Here is your code reworked:
char choice = 0;
if (cin >> choice) // check success
{
switch(choice) // choose
{
case '1': { /**/ break; }
case '2': { /**/ break; }
case '3': { /**/ break; }
default:
cout << choice
<< " is not a valid choice, please press 1, 2 or 3 and Enter"
<< endl;
}
}
I switched to switch because it's more natural than a chain of else-if for generic enumeration.

if(choice == '1')
And to answer your question, the ascii valyue for 1 is not equal to 1, but is equal to 49:
'1' == 49

choice is a char so you should use '1' to check. "1" represents a string with 1 character in it.

A value in double quotes is interpreted as a string (of type char*, which is incompatible with a char), while in single quotes it is interpreted as a char:
if(choice == '1')
The integer representation of the char'1' is not 1, but 49 (in ASCII). So you could also write
if(choice == 49)
Also, you should have an else branch to display an error message or something, and prevent the program from continuing in case an invalid input has been entered.

Related

how do you define an exact case constant with a switch statement in c++

I'm learning C++ and I don't fully understand how case works in switch statements. I have the following code:
bool accept3() {
int tries = 1;
while (tries<4) {
std::cout<<"Do you want to proceed (y or n)?\n";
char answer = 0;
std::cin>>answer;
switch(answer) {
case 'y':
return true;
case 'n':
return false;
default:
std::cout<<"Sorry, but I don't understand that.\n";
tries ++;
}
}
std::cout << "I'll take that as a no.\n";
return false;
}
int main()
{
//accept();
//accept2();
accept3();
}
It works as expected when you input, 'y', 'n', or any other single character that does not meet the two defined cases.
When you input any string of characters that begins with n, it still takes that as the 'n' case. Why does it do this? How can I make this more exact, so that it ONLY accepts 'n' and not 'no', 'no way' or any other string beginning with 'n'.
Thank you!
This is tricky because if you input text with spaces into the terminal, like "d d d y", then you'll see the loop trigger 4 times in a row because "cin >> answer" breaks the line into separate inputs (this is called tokenization).
Here's code demonstrating how to properly parse an entire line of input as one menu command:
#include <iostream>
#include <string>
bool accept3() {
int tries = 1;
while (tries < 4) {
std::cout << "Do you want to proceed (y or n)?\n";
std::string answerStr;
std::getline(std::cin, answerStr);
char answer = '\0';
if (answerStr.size() == 1) {
answer = answerStr[0];
}
switch (answer) {
case 'y':
return true;
case 'n':
return false;
default:
std::cout << "Sorry, but I don't understand that.\n";
tries++;
}
}
std::cout << "I'll take that as a no.\n";
return false;
}
int main()
{
//accept();
//accept2();
accept3();
}
When you input any string of characters that begins with n, it still takes that as the 'n' case. Why does it do this?
Because you are asking cin to read a single char, so that is what it does. operator>>(char&) ignores leading whitespace, if any, and then reads 1 char. Any subsequent characters, if any, are left in the input buffer for later reads.
How can I make this more exact, so that it ONLY accepts 'n' and not 'no', 'no way' or any other string beginning with 'n'.
Use cin.getline() or std::getline() instead, and then compare the entire line, eg:
bool accept3() {
int tries = 1;
std::string answer;
do {
std::cout << "Do you want to proceed (y or n)?\n";
std::getline(std::cin >> std::ws, answer);
if (answer == "y")
return true;
if (answer == "n")
return false;
std::cout << "Sorry, but I don't understand that.\n";
++tries;
}
while (tries < 4);
std::cout << "I'll take that as a no.\n";
return false;
}

(c++)Input needs to be a single character, but it accepts multiple characters and checks the first letter

I'm having a problem with a program I've built.
It should take input from the user and check whether it's 'P' or 'M'.
The problem is that I only want it to work if you enter 'P' or 'M', as it is now it accepts as 'M' anything you type as long as it starts with an 'M' (eg. if you type "morse" it will accept it as 'M').
I'm not a programmer and don't have much knowledge of c++, I just made it for fun. An example of how it is:
int main(){
std::cout << "Enter 'M' or 'P'\n";
char slction;
Inputrror:
std::cin >> slction;
switch (slction) {
case 'M':
goto Morse;
break;
case 'm':
goto Morse;
break;
case 'P':
goto Text;
break;
case 'p':
goto Text;
break;
default:
std::cout << "Please only enter 'M' or 'P'\n;
goto Inputrror;
break;
}
Morse:
std::cout << "Morse\n;"
return 1;
Text:
std::cout << "Text\n;"
return 1;
}
EDIT: I tried to read the input as a string like it was suggested and it now works properly. The correct version:
int main() {
std::cout << "Enter 'M' or 'P'\n";
std::string slction;
Inputrror:
std::cin >> slction;
if (slction == "M" || slction == 'm') {
goto Morse;
}
else if (slction == "P" || slction == 'p') {
goto Text;
}
else {
std::cout << "Please only enter 'P' or 'M'\n";
goto Inputrror;
}
Morse:
std::cout << "Morse\n";
return 1;
Text:
std::cout << "Text\n";
return 1;
}
One comment before I answer:
Instead of
case 'M':
goto Morse;
break;
case 'm':
goto Morse;
break;
you could use
case 'M':
case 'm':
goto Morse;
break;
break stops the block so as long as you don't use it you can nest one after another. You can even do stuff like:
case 'M':
cout << "CAPITALIZED";
case 'm':
goto Morse;
break;
Now, to your question: you are reading a char, meaning it will only take the first letter you input. Use a string instead if you want to be able to read words too:
string slction;
cin >> slction;
PD: remember to change the case 'M' and other options' quotes to double quotes (for strings)
PD2: you can't use switch with strings, so you will have to use if/else blocks
With what was said in the first answer, additionally you could use #include <cctype> toupper() function to remove extra cases. As well as validate your input with if statements.
example validation function:
char isValid(char &selection){
std::cin >> selection;
selection = toupper(selection); // ctype.h for toupper changes all to uppercase characters
//checks to see if more than 1 character is inputed
if (std::cin.get() != '\n'){
std::cin.ignore(256, '\n'); //ignores 256 chars until newline('\n')
std::cin.clear(); // clears the input
selection = '\0'; // sets selection to null
}
return selection;
}
DEMO

Input Validation w/ numbers&strings

So I have just learnt input validation however I ran into a problem. I'm forcing the user to enter a number and not a string which works, however if the user enter a number (one that is included in the switch case) and a string then the program crashes. Any tips on what to change so the validation works on everything?
int menu(double pi) //menu for choosing a shape
{
int choice = 0;
cout << "Please select what you wish to calculate:\n\n1 - Area of a Circle\n\n2 - Circumference of a Circle\n\n3 - Area of a Rectangle\n\n4 - Area of a Triangle\n\n5 - Volume of a Cuboid\n\n ";
while (!(cin >> choice))
{
cout << "Invalid input, please enter a number of 1-5\n\n";
cin.clear();
cin.ignore(100, '\n');
}
system("CLS");
switch (choice) //switch case for each shape
{
case 1:
circleArea(pi);
break;
case 2:
circleCircum(pi);
break;
case 3:
rectanArea();
break;
case 4:
triangArea();
break;
case 5:
cubVol();
break;
default:
cout << "Invalid input! Please try again.\n\n";
break;
}
return 0;
}
The issue with using
cin >> choice
When inputting a number is that >> will stop at the first non-numeric input and as long as there was numeric input to begin with it will treat it as a valid read. That means things like 2L, 2.0, and -1T are all valid integer inputs as far as cin is concerned. It just leaves the invalid part in the stream. It is this remaining steam input that messes up the program on the next input operation.
One way to fix this is to read the input into a std::string using getline and then parse the string to make sure it contains valid input. If you want to get a int for instance the
int choice;
std::string input;
std::size_t pos;
do
{
std::cout << "Enter Choice: ";
std::getline(cin,input);
choice = stoi(input, &pos);
} while(pos != input.size());
This makes sure that you read in everything up to the pressing enter into input and that you only stop the loop once everything entered can be converted to a valid int.

C++ How to Implement Menu with Number and Letter Choices [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I want to use a menu in C++ that has options both in letters and numbers. For example, the output might be:
========================
(1) Do something
(2) Do something
(a) Do something
(b) Do something
========================
Is there a method for testing user input to determine if it is a char or int and handle it accordingly?
If I use:
int choice;
cin >> choice;
And the user inputs a char, of course cin will return an error. I'm looking for a simple method to test user input for a digit or a character and have the program react differently based on that determination.
[UPDATE]
I've found the answer I was looking for. Here's how I did it:
string choice;
cout << "Your choice: ";
cin >> choice;
if( isdigit(choice[0]) )
{
theInt = stoi(wChoice);
// do something with int
}
else if( choice[0] = 'a' )
// do menu option a
You'd better use the method isdigit in the ctype.h to check if character is a decimal digit character, and the method isalpha to check if character is alphabetic.
"For example, there could be options: 1, 2, 3, n, s."
The simplest solution I see is to have a menu selection code like
char choice;
std::cin >> choice;
switch(choice) {
case `1`:
// Do menu option one
break;
case `2`:
// Do menu option two
break;
case `3`:
// Do menu option three
break;
case `n`:
// Do menu option "n"
break;
case `s`:
// Do menu option "s"
break;
}
If you need to handle numeric choices bigger than 9, you simply use a std::string as input field:
std::string choice; // <<<
std::cin >> choice;
in turn a switch statement cannot be used any more and you have to change it to an if/else if/else cascade:
if(choice == "1") {
// Do menu option one
}
else if(choice == "2") {
// Do menu option two
}
// ...
else if(choice == "42") {
// Do menu option fortytwo
}
else if(choice == "n") {
// Do menu option "n"
}
else if(choice == "s") {
// Do menu option "s"
}
For this, you'll need to read in the input as a string, then parse it to see if it's an alphabetic character or if it's a numeric string. Something along the lines of this (warning, I'm mostly a C programmer, so using C-strings instead of real strings):
#define INPUT_SIZE 8
char input[INPUT_SIZE]; // change size as appropriate
cin.getline(input, INPUT_SIZE);
if (cin.good())
if(input[0] >= '0' && input[0] <= '9') {
int value = atoi(input);
} else if(input[0] >= 'a' && input[0] <= 'z') {
char value = input;
}
}
Naturally, values need different names and actual code paths to deal with them, especially as C++ doesn't have a good built-in "either" type that I know of.
Alternatively, just treat everything as a character, assuming all numeric options are a single character, and test as '0' instead of 0.

Display the output when type specifed word as first letter and ignore the other words after it

After this question I figured out that using char as input will avoid the infinite loop caused by typing characters for input which is using int. But now I had met another problem.
When I typed the code below:
#include <iostream>
void language();
int main() {
language();
}
void language() {
char choice;
// Ask user for something and input
std::cout << "Press 1 to exit the program\n\n";
std::cin >> choice;
// Getting user's input and run the code below and find for specific words
switch(choice) {
case '1':
std::cout << "\n\nEnding program...";
return 0;
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}
}
When I compile it I didn't get any errors or warnings. But when I type 12 or similar word with 1 at first, the program will be ended.
And before answering me, I still learning C++. (By the way I don't think I really need to say this?) And because this I didn't know how to solve this. What's happening to my code?
As you want a char from the input, std::cin will just get the first character you type in the input and assign to choice. It will ignore the following characters.
That is, you will enter in the first case of your switch/case condition and return.
It depends on what are the inputs you expect from the user. If you expect only numbers, I suggest you to use an int :
#include <limits> // needed for std::numeric_limits
void language() {
int choice;
// ^^^^
// Ask user for something and input
std::cout << "Press 1 to exit the program\n\n";
std::cin >> choice;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Getting user's input and run the code below and find for specific words
switch(choice) {
case 1:
std::cout << "\n\nEnding program...";
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}
}
Working live example.
Your code is exiting when you enter input starting with character 1.
You want the choice as string, not char since char only contains one character. Also you don't need break after the return statement
char choice;
will just receive a single character from standard input.
so all digits starting with 1 will end your program
instead use int choice; and change case to case 1:
#include<limits>
//...
int choice;
//...
std::cout << "Press 1 to exit the program\n\n";
while(true)
{
if (std::cin >> choice)
break ;
else {
std::cout<<"Not an integer !"<<std::endl;
std::cin.clear() ;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),
'\n') ;
}
}
switch(choice) {
case 1:
//...
break;
default:
std::cout << "\n\nPlease type the specific number.\n\n";
language();
break;
}