I am trying to learn C++ and so far i have been on the right but i have been have a simple problem and i am getting confused on the case statement i have known how to deal with the if statement and i understand it very well,i working classes and methods in my code below which works perfectly i want to know how i can change this if statement and replace it with the case statement,when i try it its not working but this is my code for the if statement how can i make it work if i want to use case instead of if??thanks in advance
my code
void SetType(){
cout<<"Book SetType"<<endl;
Choice:
cout<<"Please Select from the list: \n 1- Technical literature \n 2- Fiction literature \n 3- Textbook"<<endl;
int i;
cin >> i;
if ((i>0)&(i<=3)) {
if (i==1) Type="Technical literature";
if (i==2) Type="Fiction literature";
if (i==3) Type="Textbook";
}
else
{
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
}
}
switch(i) {
case 1:
Type="Technical literature";
break;
case 2:
Type="Fiction literature";
break;
case 3:
Type="Textbook";
break;
default:
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
}
A switch / case is totally fit for your situation. Use a switch / case when you have discrete values you can test on a single variable, in your case i.
It works by defining each case and a default one in case the variable doesn't match with any case. Here's what your code would look like with a switch / case:
switch(i)
{
case 1:
Type="Technical literature";
break;
case 2:
Type="Fiction literature";
break;
case 3:
Type="Textbook";
break;
default:
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
}
break is used to prevent the code from one case to continue executing the code of the following case.
I would strongly advise you learn better methods than using a goto to go back to your Choice selection.
Here's a new version with a slightly better "input loop", without using goto
void SetType()
{
cout << "Book SetType" << endl;
bool validChoice;
do
{
validChoice = true; // Invalidate it in case of wrong choice
cout << "Please Select from the list: \n 1- Technical literature \n 2- Fiction literature \n 3- Textbook" << endl;
int i;
cin >> i;
switch(i)
{
case 1:
Type="Technical literature";
break;
case 2:
Type="Fiction literature";
break;
case 3:
Type="Textbook";
break;
default:
cout << "Error you entered a wrong choice" << endl;
validChoice = false;
cin.clear();
string dummyLine;
getline(cin, dummyLine);
}
} while(validChoice == false);
}
I added some code to remove input that is not a number, otherwise cin will keep failing.
void SetType(){
cout<<"Book SetType"<<endl;
Choice:
cout<<"Please Select from the list: \n 1- Technical literature \n 2- Fiction literature \n 3- Textbook"<<endl;
int i;
cin >> i;
switch(i)
{
case 1:
{
Type="Technical literature";
break;
}
case 2:
{
Type="Fiction literature";
break;
}
case 3:
{
Type="Textbook";
break;
}
default:
{
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
break;
}
}
}
void SetType(){
cout<<"Book SetType"<<endl;
Choice:
cout<<"Please Select from the list: \n 1- Technical literature \n 2- Fiction literature \n 3- Textbook"<<endl;
int i;
cin >> i;
switch(i) {
case 1: Type="Technical literature"; break;
case 2: Type="Fiction literature"; break;
case 3: Type="Textbook"; break;
default:
cout << "Erorr you entered a wrong choice" << endl;
goto Choice;
}
}
P.s. Many folks break into a cold sweat and have palpitations at the sight of a goto.
Related
Code for a blackjack card counting program.
the issue is that it does not exit the while loop upon receiving no cin input from the user.
for example)
User would input x chars and then hit enter to exit the while loop.
#include<iostream>
using namespace std;
int main(){
int count = 0;
char currcard;
cout<<"Enter cards seen on table: "<<endl;
while (cin>>currcard)
{
switch (currcard)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
count++;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
count--;
break;
default:
cout<<"Invalid Entry";
break;
}
}
cout <<"Current count: "<< count << endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
Expecting program to exit when enter is hit by user
You can use cin.get() like this.
while (cin>>currcard)
{
// your logic
if (cin.get() == '\n') {
break;
}
}
In this way, your input is supposed to be something like 1 2 3 4 A J Q ending with Enter.
EDIT
As OP wants undetermined length of input, I suggest to switch the input itself from char to std::string.
This way access is gained to more intuitive and effective I\O operations:
#include <iostream> // std::cin, cout, endl
#include <string> // std::string: can omit this line
#include <cctype> // isspace(): can omit
int main(){
int count = 0;
std::string currcard{""};
std::cout << "Enter cards seen on table: "<< std::endl;
std::getline(std::cin, currcard);
for (char c : currcard) {
if (isspace(c))
continue;
switch (c) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
++count;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
--count;
break;
default:
//std::cout << "Invalid Entry\n";
break;
}
}
std::cout <<"Current count: "<< count << std::endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
Notice I have added a check for white spaces, and removed the message for invalid entries: both simply get ignored. But if needed that line can be uncommented.
Old solution
You can use cin.getline() as suggested in the comments, in conjunction with a flag that triggers exit from the loop once three inputs are given:
#include <iostream>
int main(){
static int count = 0, flag = 0;
char currcard;
std::cout << "Enter cards seen on table: "<< std::endl;
while(std::cin.getline(&currcard, 3)){
switch (currcard)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
++count;
break;
case '7':
case '8':
case '9':
break;
case 'A':
case 'J':
case 'Q':
case 'K':
--count;
break;
default:
std::cout << "Invalid Entry\n";
--flag;
break;
}
++flag;
if (flag == 3)
break;
}
std::cout <<"Current count: "<< count << std::endl;
//user enter cards seen on table and if below 7 increment
//based on count the program returns if you should hit or quit
return 0;
}
There is also a flag decrement for invalid entries.
I'm in the middle of taking an online C++ course, and I've been having issues with this homework problem. I tried reaching out to my professor twice, but he hasn't responded. I've sought out many solutions, but since I'm new in the course, many of the solutions involve using techniques I haven't learned yet (like character arrays.) I can get the conversion program to work, but I want the program to allow to process as many user inputs as the user wants.
When I run the program, the program accepts my first input that is 'y' or 'Y' to run the program. It then will ask for a string to convert to the telephone number. This works. However, I need the program to ask the user if they want to run the program again to convert another string to a telephone number or to terminate the program.
I put in another cin at the end of the first while loop to prompt for another input, but it gets skipped over everytime and keeps doing the while loop.
Question: Why is the last prompt to repeat the program get skipped every time I've run it? What am I missing?
Here's the problem and what I've done so far:
Problem:
To make telephone numbers easier to remember, some companies use
letters to show their telephone number. For example, using letters,
the telephone number 438-5626 can be shown as GET LOAN.
In some cases, to make a telephone number meaningful, companies might
use more than seven letters. For example, 225-5466 can be displayed as
CALL HOME, which uses eight letters. Instructions
Write a program that prompts the user to enter a telephone number
expressed in letters and outputs the corresponding telephone number in
digits.
If the user enters more than seven letters, then process only the
first seven letters.
Also output the - (hyphen) after the third digit.
Allow the user to use both uppercase and lowercase letters as well as
spaces between words.
Moreover, your program should process as many telephone numbers as the
user wants.
My code so far:
#include <iostream>
using namespace std;
int main()
{
char letter, runLetter;
int counter = 0;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
while (runLetter == 'y' || runLetter == 'Y')
{
cout << "Enter in a telephone number as letters: " << endl;
while (cin.get(letter) && counter < 7 )
{
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter-32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
}
cout << "Goodbye. " << endl;
return 0;
}
Thanks in advance for any help. I know this might be an easy solution, but I've been tinkering with this program for a couple of days now.
Tried moving the last user prompt in and out of each if/else structure and different while loops. Not sure what I can do to make the program take a new input after the first iteration.
A very good hint to your problem is the comment from #AlanBirtles. Also I know you are a beginner and you may not know about std::string but you should use it because you are learning C++ not C. in a nutshell, it is a C++ way of dealing with char arrays, also better than just that.
Here is your code with minimum changes to do what you are looking for. The main changes is the use of std::string, the use of std::getline and the definition of the counter inside the while loop.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char letter;
std::string runLetter;
std::string number;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline( std::cin, runLetter);
while (runLetter == "y" || runLetter == "Y")
{
int counter = 0;
cout << "Enter in a telephone number as letters: " << endl;
std::getline(std::cin, number);
for (int i = 0; i < number.size(); i++)
{
letter = number[i];
if (counter < 7)
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter - 32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline(std::cin, runLetter);
}
cout << "Goodbye. " << endl;
return 0;
}
I found the following errors in your code:
You do not reset the variable counter to 0 in the second loop iteration, so that counter has the value 7 in the entire second loop iteration, which causes the inner while loop not to be entered. This bug should be clearly visible when running your program line by line in a debugger while monitoring the values of all variables.
You always read exactly 7 characters from the user per loop iteration, which is wrong. You should always read exactly one line per loop iteration. In other words, you should read until you find the newline character. You can ignore every character after the 7th letter, but you must still consume them from the input stream, otherwise they will be read in the next loop iteration(s), which you do not want. However, this does not mean that you can simply ignore everything after the 7th character, because the number of characters is not necessarily identical to the number of letters. For example, if a 7 character string has one space character, then it only has 6 letters. As stated in the task description, the user should be allowed to enter spaces in the string.
I know people will immediately look at the title and just say: "Use String" or "Char can only be length of 1" but there are problems with those.
For the first, due to later on in the code using a switch statement my variable must stay as a char so that it does not cause any errors, and for the second answer during testing I found out that even if I entered a multi-length input it would just run each character into the switch statement separately which I do not want to happen. Any help is welcomed, oh and here's the code:
char input;
do {
cout << "Please enter a number from 1 to 4.";
cin >> input;
if (sizeof(input)!=1) {
cout << "Please just enter a number";
}
else {
switch (input) {
case '1': {
cout << "One";
break;
}
case '2': {
cout << "Two";
break;
}
case '3': {
cout << "Three";
break;
}
case '4': {
cout << "Four";
break;
}
default:
cout << "Enter only a number from 1-4!";
}
}
} while ((input) != '4');
Note that I have at least attempted to use strlen and the size functions but to no avail.
Well, use string, because char can only be length of 1.
std::string input;
std::cin >> input;
if (input.size() != 1) {
std::cout << "Wrong input";
} else {
switch (input.front()) {
case '1':
// ...
}
}
This question already has answers here:
How do I select a range of values in a switch statement?
(18 answers)
Closed 2 years ago.
How does one accept more than one value for a single case in C++? I know you can make a range of values for one case (e.g. case 1..2) in some other languages, but it doesn't seem to be working in C++ on Xcode.
int main() {
int input;
cin >> input;
switch (input) {
case 1:
cout << "option 1 \n";
break;
case 2..3: //This is where the error occurs
cout << "option 2 and 3 \n";
break;
default:
break;
}
return 0;
}
The program shows an error saying "Invalid suffix '.3' on floating constant" where the range is.
You can "fall through" by having sequential case statements without a break between them.
switch (input) {
case 1:
cout << "option 1 \n";
break;
case 2:
case 3:
cout << "option 2 and 3 \n";
break;
default:
break;
}
Note that some compilers support range syntax like case 50 ... 100 but this is non-standard C++ and will likely not work on other compilers.
You could simply do:
switch (input) {
case 1:
cout << "option 1 \n";
break;
case 2: [[fallthrough]]
case 3:
cout << "option 2 and 3 \n";
break;
default:
break;
}
Note that case 2 ... 3 is called case ranges, and is a non-standard gcc extension that you could use.
You can't do a range of values, but you can do multiple values:
switch (input) {
case 1:
cout << "option 1 \n";
break;
case 2: case 3: case 4:
cout << "option 2 or 3 or 4\n";
break;
default:
break;
}
You need to use spaces between them with three(...)
int main() {
int input;
cin >> input;
switch (input) {
case 1:
cout << "option 1 \n";
break;
case 2 ... 3: //This is where the error occurs
cout << "option 2 and 3 \n";
break;
default:
break;
}
return 0;
}
OK, here is a simple code example:
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
}
Obviously I could pull my hair out with a while(answer != 'Y' || answer !=...) But is there a more elegant way of simply returning to the first case after executing the default case? So if a user enters the wrong letter, I simply ask them the question again until they type an acceptable response?
No this isn't homework or anything. I'm working through Dawson's C++ Game Programming book, and I wanted to jazz up the program example a little by allowing the user to keep or trade an item. I got all that working beautifully, but if a wrong response is entered it just shows the contents of the inventory and exits. I wanted to get that right. Force the user to enter a correct response, then show the updated inventory afterwards.
Appreciate the help!
UPDATE!
You have all given me so many different approaches to this - I really appreciate it! I admit I probably did not design this switch statement correctly and I apologize for the contradiction. I will try each of your suggestions and post back here, choosing one as answer. Thank you!
OK, I have just gone through all of your answers, trying most of them with my code. I have chosen the simplest, most elegant solution as the answer to my question. But you all have helped me to see different ways of looking at this, and I understand so much more about switch statements now. Using it in fact in place of a while loop in a tutorial I am following right now at YouTube by user What's A Creel?
I really appreciate all your help! I feel that I have really accomplished a lot in my programming practice today. You guys (and gals) are all awesome!
UPDATED AND COMPLETE CODE:
#include <iostream>
#include <string>
using namespace std;
// This program displays a hero's inventory
int main()
{
const int MAX_ITEMS = 4;
string inventory[MAX_ITEMS];
int numItems = 0;
inventory[numItems++] = "Rusty Battle Axe";
inventory[numItems++] = "Leather Armor";
inventory[numItems++] = "Wooden Shield";
cout << "Inventory:\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
cout << "\nYou open a chest and find a Lesser Healing Potion.";
inventory[numItems++] = "Lesser Healing Potion";
cout << "\nInventory\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
cout << "\nYou also find a Short Sword.";
if(numItems < MAX_ITEMS)
{
inventory[numItems++] = "Short Sword";
}
else
{
cout << "\nYou have too many items and can't carry another.";
cout << "\nWould you like to trade the " << inventory[0] << " for the Short Sword? ";
}
while (true)
{
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest." << endl;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest." << endl;
break;
default:
cout << "\nThat was an invalid response!";
cout << "\nWould you like to trade the " << inventory[0] << " for the Short Sword? ";
continue;
}
break;
}
cout << "\nInventory:\n";
for(int i = 0; i < numItems; ++i)
{
cout << inventory[i] << endl;
}
return 0;
}
You can use a one-shot loop that breaks at the end and use continue to jump back to the top:
while(true)
{
switch(...) {
//...
default:
continue;
}
break;
};
Perhaps a nicer way is to define a set of valid letters, especially if you'll do this kind of thing everywhere in your code:
char GetChoice( const string & prompt, const string & valid_choices )
{
while( cin.good() )
{
cout << prompt << " " << flush;
char c;
if( !cin.get(c) ) break;
size_t pos = valid_choices.find(toupper(c));
if( pos != string::npos ) return valid_choices[pos];
}
return 0; // Error condition.
}
And use like this:
switch( GetChoice("Do you want cake?", "YN") )
{
case 'Y':
cout << "Cake for you.\n";
break;
case 'N':
cout << "No cake for you.\n";
break;
case 0:
exit(1); // Error occurred
}
bool valid;
do
{
char answer;
cin >> answer;
switch (answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
valid = true;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
valid = true;
break;
default :
cout << "\nThat was an invalid response.";
valid = false;
break;
}
}
while (!valid);
Well, add a loop and it will "loop back" wherever you want.
Note that the entire body of switch is just one long statement with labels in it. It works as any other statement, once you entered it through one of the labels. Just like an ordinary C++ statement will not "loop back" for you by itself unless you make it a cycle or use goto, neither will the body of switch "loop back" for you by itself.
So, if you want to transfer control back - use the appropriate language construct. You can inject goto right into the body of that statement and it will work as usual.
switch(answer)
{
case 'y':
case 'Y':
FIRST_OPTION:
...
break;
default :
...;
goto FIRST_OPTION; // Jump to first option
}
You might also want to take a look at Duff's device for a more intricate example of control transfer inside switch statement.
However, your question seems to contradict itself. You state that you want to ask the user for input again, if the answer was invalid. But the user input is requested and accepted outside of switch. Why do you say then that you want to return to the first option of switch???
Use a goto statement in the default section to go back to the input part
Here is one approach:
bool done = false;
while (!done) {
char answer;
cin >> answer;
done = true;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
done = false;
}
}
Use a while or do while loop.
Eg:
char answer;
bool loopback = true;
do
{
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
loopback = false;
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
loopback = false;
break;
default :
cout << "\nThat was an invalid response.";
loopback = true;
}
}
while (loopback);
You can use label and goto statement. Label the statement where you are asking the user to input and add a goto statement in default case.
Ex::
AskQuestion:
cout << "Press 'Y' for Short Sword Or 'N' for Rusty Battle Axe" << endl;
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
goto AskQuestion ;
}
Alternative way is to use do-while loop with condition while(answer != 'Y' || answer !=...) as you have already commented in the question. Ex::
do{
cout << "Press 'Y' for Short Sword Or 'N' for Rusty Battle Axe" << endl;
char answer;
cin >> answer;
switch(answer)
{
case 'y':
case 'Y':
inventory[0] = "Short Sword";
cout << "\nYou place the Rusty Battle Axe in the chest.";
break;
case 'n':
case 'N':
inventory[0] = "Rusty Battle Axe";
cout << "\nYou leave the Short Sword in the chest.";
break;
default :
cout << "\nThat was an invalid response.";
}
}while( answer != 'Y' || answer != 'y' || answer != 'N' || answer != 'n' ) ;