C++: Using multiple conditions in switch statements - c++

I am in a beginning C++ programming class and I need help with nesting switch statements and using multiple conditions, because I have to translate a program I already wrote from if/else statements to switch statements, because I didn't know I was supposed to use the switch statement.
For example, how do I change something like:
if (temperature >= -459 && temperature <= -327)
{
cout << "Ethyl Alcohol will freeze.\n";
}
else if (temperature >= -326 && temperature <= -30)
{
cout << "Water will freeze.\n";
}
else if ...
{
}
else
{
}
Into a switch/case statement? I can get the first level, but how do I nest and have multiple conditions like the temperature statements above?

Switch statements work like this:
int variable = 123; // or any other value
switch (variable)
{
case 1:
{
// some code for the value 1
break;
}
case 12:
{
// some code for the value 12
break;
}
case 123:
{
// some code for the value 123
break;
}
case 1234:
{
// some code for the value 1234
break;
}
case 12345:
{
// some code for the value 12345
break;
}
default:
{
// if needed, some code for any other value
break;
}
}

First of all, this question is in C and not in C++. C++ inherited most of the C language, including the switch-case.
You can't do this with a switch, unless you start enumerating all the values one by one, like this:
switch (temperature) {
case -459:
case -458:
....
case -327: <do something>; break;
case -326:
.....
}
This is because in C, switch-case is simply translated to a series of if-goto statements, with the cases just being the labels.

In your case, your stuck with an if-else-if ladder.
You could use a lookup table that has temperatures and the text to print:
struct Temperature_Entry
{
int min_temp;
int max_temp;
const char * text_for_output;
};
static const Temperature_Entry temp_table[] =
{
{-459, -327, "Ethyl Alcohol will freeze.\n"},
{-326, -30, "Water will freeze.\n"},
};
static const unsigned int entry_count =
sizeof(temp_table) / sizeof(temp_table[0]);
//...
int temperature;
for (unsigned int i = 0; i < entry_count; ++i)
{
if ( (temperature >= temp_table[i].min_temp)
&& (temperature < temp_table[i].max_temp))
{
std::cout << temp-table[i].text_for_output;
}
}

As many have pointed out, you cannot use switch case for ranges and dynamic formulas. So if you want to use them anyway, you will have to write a function which takes a temperature and returns a temperature range out of a pre-known set of temperature ranges. Then, finally, you can use a switch/case for the temperature ranges.
enum TemperatureRange { FrigginCold, UtterlyCold, ChillinglyCold, Frosty, ... };
TemperatureRange GetRange( int temperature );
// ...
switch( GetRange( temperature ) )
{
case FrigginCold: cout << "The eskimos vodka freezes."; break;
case UtterlyCold: cout << "The eskimo starts to dress."; break;
// ...
}

Related

how to replace a value of a variable inside code from user input?

i am trying to add a developer mode in my program. since duty of car defers every month,i want give my user permission to change every single variables in my program alike duty lccost yen2taka freight
#include <iostream>
using namespace std;
class A
{
public:
int carbid,duty;
void Input()
{
cout<<"please insert the car price you want to bid for(in yen): ";
cin>>carbid;
cout<<"duty of the car: ";
cin>>duty;
}
int Exportcost()
{
int exportcost;
int servicechrg=10;
int freight=20;
exportcost=servicechrg+freight+carbid;
return exportcost;
}
int Yen2taka()
{
int yen2taka;
int taka2dollarrate=10;
int dollar2yen=1;
yen2taka=((Exportcost())/dollar2yen)*taka2dollarrate;
return yen2taka;
}
int Importcost()
{
int importcost;
int lccost=10;
int cnfcost=20;
importcost=lccost+cnfcost;
return importcost;
}
int Totalcosting()
{
int total;
int myprofit=10; //80000
total=myprofit+Importcost()+Yen2taka();
cout<<total;
return total;
}
void summary()
{
cout<<
}
};
int main()
{
x:
A ob;
ob.Input();
ob.Exportcost();
ob.Yen2taka();
ob.Importcost();
ob.Totalcosting();
int ch;
cout<<"press 1 to see the summery of the costing or 2 to restart costing again"<<endl;
cin>>ch;
switch(ch)
{
case 1:
ob.summary();
break;
case 2:
goto x;
}
}
At first, you should collect these parameters in a separate class:
class Configuration // maybe you find a better name...
{
int m_servicechrg = 10; // default
int m_freight = 20;
// ...
public:
int servicechrg() { return m_servicechrg; }
void servicechrg(int value); { /* check some limits? */ m_servicechrg = value; }
int freight() { return m_freight; }
void freight(int value); { /* check some limits? */ m_freight = value; }
// ...
};
// will allow you to do:
// C c; std::cout << c;
ostream& operator<<(ostream& s, Configuration const& c)
{
// which ever formatting is appropriate...
s << c.servicechrg() << ' ' << c.freight();
return s;
}
The setters could alternatively return bool to indicate invalid values.
Now you can use this class within main:
Configuration c;
A a;
int cost = a.exportCost(c); // you'd have to adjust signatures...
int value;
switch(ch)
{
case 4:
if(stc::cin >> freight) // catches invalid user input!
// one ALWAYS should do, otherwise you might end up in
// your program not working any more
{
c.freight(value);
// or, if you have:
if(!c.freight(value))
{
// some appropriate error message
// (it's better not to output in the setter, you are more flexible this
// way – maybe you want different messages at different occasions?)
}
}
else
{
// appropriate error handling
}
break;
default:
// handling invalid user input
// again, you always should; but stream state is not in error state,
// so you just can print appropriate error message
break;
}
See this answer for how to correctly handle stream errors.
If you wonder about the differences in error handling: First case is met if user enters non-numerical input, such as ss, second case, if input is numerical, but out of valid range (77).
Now if you don't want to pass the configuration as parameter all the time, you could make a global variable from (but careful, there are some dangers with global variables, use them as sparely as possible) or implement the singleton pattern.
Side notes: goto can be a fine tool sometimes, but it is a dangerous one (and the label's name x isn't a good one, prefer a name that clearly shows intention, such as REENTRY_POINT, LOOP_START, ...). If you can get along without unreasonable effort, prefer such variants:
bool isRunning = true;
do
{
// ...
case 2:
isRunning = false;
break;
}
while(isRunning);
Sure, an additional variable, an additional check; unfortunately, you cannot use break to exit a (pseudo-) endless loop (for(;;)) (but don't apply this pattern for nested loops, then it gets more and more unreadabla – and ineffcient: bool isExit = false; for(int i = 0; !isExit && i < n; ++i) { for(j = 0; j < n; ++j) { isExit = true; break; } } – see what I mean?). A variant might be:
for(;;)
{
switch(ch)
case 1:
// ...
//break; <- replace
continue;
case 2:
//
break;
} // end of switch
break; // break the surrounding for(;;) loop
}
But that's not really nice either.
A pretty nice variant allowing to exit the loop in the given case, as there isn't anyhting to do afterwards:
for(;;)
{
switch(ch)
{
case 2:
// maybe yet some cleaning up here
return 0;
default:
// ...
break;
}
}
Drawback: The function's exit point possibly is deeply nested inside the code.
There are yet other tricks to allow this pattern, like packing sub-sections of code in a lambda having a return inside and call that one directly. But that now really starts going beyond the scope...
Finally, if you insist on goto, my variant would rather be:
for(;;)
{
switch(ch)
{
case 2:
// ...
goto LOOP_EXIT;
default:
// ...
break;
}
}
LOOP_EXIT:
return 0; // e. g. main
(void)0; // if there isn't anything to do in the function any more
// (labels require an instruction afterwards!)
There won't be a hidden loop now and it is more obvious what you actually are doing. Currently, not really an issue, but if your code grows, the hidden loop gets more and more difficult to spot.
In such cases, I clearly mark the gotos so that another coder can immediately spot the critical code points:
///////////////////////////////////////////////////
// possibly some comment why applying this pattern
goto SOME_LABEL;
///////////////////////////////////////////////////
One could do the same with deeply nested function exit points (return).

switch case with string in c++

I want to write a switch case with string. I used enum and I write this:
string enum {
next = 0,
prev = 1,
ext = 2
}order;
while(true)
{
cin >> order;
switch(order)
{
case 0:
//do order0
break;
case 1 :
//do order 1
break;
case 2 :
//do order2
return;
break;
default:
cout << "Bad input";
break;
}
}
but the result is this error:
error C2236: unexpected token 'enum'. Did you forget a ';'?
what's the reason of this error?
is there any other way to write a switch with string?
Don't fight the language. You can't switch on strings in C++ as you know.
Use if, else if instead.
You do see various attempts crop up from time to time. Maps, enums, and hashes being three I can think of. But they just obfuscate. And you'll probably need break statements which worsen things further. (If follow through would have been useful then structure the equivalent if block accordingly).
Your ; error is due to string enum being syntatically invalid.
What's this :-
string enum {
next = 0,
prev = 1,
ext = 2
}order;
It should be:-
enum Mydata {
next = 0,
prev = 1,
ext = 2
};
The error comes from:
string enum {
next = 0,
prev = 1,
ext = 2
}order;
This is invalid syntax, enum and string are both types and you can't make an instance of a type with another reserved keyword.
Instead you want to declare the enum like this:
enum order{
next = 0,
prev = 1,
ext = 2
};
But chances are that you really don't want to go about solving your problem in this way. A simple way is just using conditionals with if statements or perhaps std::map instead.
cin >> order;
if(order == "0"){
}else if( order == "1"){
}else{
}
The reason why is because'string enum' is not valid.
Here is an example:
enum Orders{
next=0,
prev=1,
ext=2
};
while(true)
{
int oder=-1;
cin>>order;
switch(order)
{
case next:
//do something
break;
case prev:
//do something else
break;
case ext:
//something else
break;
default:
cout << "error\n";
break;
}
}

c++ switch [Error] 'x' cannot appear in a constant-expression

im trying to execute this script its for my university
int main()
{
int x;
double y;
Provo:
cout<<"Vlera e X: ";
cin>>x;
switch(x)
{
case ((x)<(0.9)):
y=x*x;
break;
case (x==0.9):
y=2*x;
break;
case 'x>0.9':
y=x-3;
break;
}
cout<<"\n\n";
return 0;
}
this is teh code and the error is:
17 10 ....\Untitled1.cpp [Error] 'x' cannot appear in a constant-expression
someone help please?
I think you have misunderstood how to use the switch statement. switch is used to branch your code based on the condition, in your case x, taking different integral values. It is not suitable for use with double values like you do.
A correct switch expression would look like:
switch(x)
{
case 1:
y=x*x;
break;
case 2:
case 3:
case 4:
y=2*x;
break;
case 5:
y=x-3;
break;
}
To accomplish what you want, use if else instead, for example:
if (x < 0.9) {
y=x*x;
else if(x == 0.9) {
y=2*x;
} else {
y=x-3;
}
However, comparing floating point values for equality is a bad idea. It is usually better to do something like:
double epsilon = <some small value>;
if (x < 0.9-epsilon) {
y=x*x;
else if(x > 0.9+epsilon) {
y=x-3;
} else {
y=2*x;
}

Adding split-screen multiplayer to c++ game

I am coding for the NDS in c++ with libnds, but this question is not NDS-Specific. I currently have a text-based game in which the top screen just displays a logo, and you play on the bottom screen.
So I want to add a type of single-DS multiplayer in which one player plays on the top screen, and the other on the bottom. I dont have a problem with setting up the text engine with both screens, I just need to find a method of efficiently coding in multiplayer. Below I wrote a summary or simplified version of it.
Note: consoleClear() clears the screen and the only spot where the game stops is att the pause function.
//Headers
void display(int x,int y,const char* output))
{
printf("\x1b[%d;%dH%s", y, x,output);
}
void pause(KEYPAD_BITS key) //KEYPAD_BITS is an ENUM for a key on the NDS
{
scanKeys();
while (keysHeld() & key)
{
scanKeys();
swiWaitForVBlank();
}
while (!(keysHeld() & key))
{
scanKeys();
swiWaitForVBlank();
}
return;
}
void pause() //Only used to simplify coding
{
pause(KEY_A);
return;
}
int main(void)
{
//Initializations/Setup
while (1)
{
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
pause();
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
pause();
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Leave my house right now!!!");
pause();
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
pause();
consoleClear();
display(6,7,"I'll see you tomorrow.");
pause();
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
pause();
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
pause();
consoleClear();
display(6,7,"Never come back!!");
pause();
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
pause();
}
}
}
}
I know gotos are confusing and can be considered a bad habit, but I cant think of a better way. My version of integrating multiplayer:
//Headers and same functions
int game(int location)
{
switch (location)
{
case 1: goto one; break;
case 2: goto two; break;
case 3: goto three; break;
case 4: goto four; break;
case 5: goto five; break;
case 6: goto six; break;
case 7: goto seven; break;
case 8: goto eight; break;
case 9: goto nine; break;
case 10: goto ten; break;
default: break;
}
if (rand()%2==1) //Say Hello
{
if (rand()%3!=1) //To Friend (greater chance of friend than enemy)
{
display(6,7,"Hello Friend!");
display(6,8,"Good greetings to you.");
return 1;
one:;
consoleClear(); //Clears text
display(6,7,"Would you like to come in?");
return 2;
two:;
//Normally more complex complex code (such as interactions with inventories) would go here
}
else //To enemy
{
display(6,7,"Hello enemy!");
display(6,8,"I hate you!");
return 3;
three:;
consoleClear();
display(6,7,"Leave my house right now!!!");
return 4;
four:;
}
}
else //Say goodbye
{
if (rand()%4==1) //To Friend (lesser chance of friend than enemy)
{
display(6,7,"Goodbye Friend!");
display(6,8,"Good wishes to you.");
return 5;
five:;
consoleClear();
display(6,7,"I'll see you tomorrow.");
return 6;
six:;
consoleClear();
display(6,7,"Wait, I forgot to give you this present.");
return 7;
seven:;
}
else //To enemy
{
display(6,7,"Goodbye enemy!");
display(6,8,"I hate you!");
return 8;
eight:;
consoleClear();
display(6,7,"Never come back!!");
return 9;
nine:;
consoleClear();
display(6,7,"Good riddance!"); //I think I spelt that wrong...
return 10;
ten:;
}
return -1;
}
}
int main(void)
{
//Initializations/Setup
int location1 = -1, location2 = -1;
location1 = game(location1);
location2 = game(location2);
while (1)
{
scanKeys(); //Whenever checking key state this must be called
if (keysDown() & KEY_A) //A key is used to continue for player1
location1 = game(location1);
if (keysDown() & KEY_DOWN) //Down key is used to continue for player2
location2 = game(location2);
}
}
Aside from this method being a bad practice, in the actual source code, I have hundreds of gotos I would need to add which would be too time consuming.
Any help is appreciated. If anyone has the slightest of a question, or answer, please ask/reply.
Edit: Though it is not preferred to do so, I am willing to rewrite the game from scratch if someone has a method to do so.
Using if-else conditional statements for each case is a simple solution that comes first to mind.
For example:
int game(int i){
if(i == 1){
//first case code here.
}
else if(i == 2){
//second case code here.
}
//....
return 0;
}
The code in each case can even be put in other functions that will be invoked depending on each condition.
This will probably be enough for your case.
A more flexible solution (but much more complex) is a dispatch table.
The idea is to have separate functions with each desired functionality, and put pointers of them in an array. Then, you can call them by indexing the table, using those function pointers. This can be extremely helpful if you have a sequence of executions (function invokes) to be done and you want to set it done easily, or you want to have different results depending on your input, without changing your program.
There is an example below.
This code can be used in C too, if you replace std::cout with printf and iostream with stdio library.
#include <iostream>
using namespace std;
// Arrays start from 0.
// This is used for code
// readability reasons.
#define CASE(X) X-1
typedef void (*chooseCase)();
// Functions to execute each case.
// Here, I am just printing
// different strings.
void case1(){
cout<< "case1" << endl;
}
void case2(){
cout<< "case2" << endl;
}
void case3(){
cout<< "case3" << endl;
}
void case4(){
cout<< "case4" << endl;
}
//Put all the cases in an array.
chooseCase cases[] = {
case1, case2, case3, case4
};
int main()
{
//You can call each scenario
//by hand easily this way:
cases[CASE(1)]();
cout << endl;
//Idea: You can even set in another
// array a sequence of function executions desired.
int casesSequence[] = {
CASE(1), CASE(2), CASE(3), CASE(4),CASE(3),CASE(2),CASE(1)
};
//Execute the functions in the sequence set.
for(int i = 0; i < (sizeof(casesSequence)/sizeof(int)); ++i){
cases[casesSequence[i]]();
}
return 0;
}
This will print at the output:
case1
case1
case2
case3
case4
case3
case2
case1

Using a function call in a case statement label

Can you have a function call as a case statement label. For instance:
char x
switch(x)
{
case isCapital():
capitalcount++;
break;
case isVowel():
vowelcount++;
break;
.
.
.
.
.
}
Is this permitted within C++?
The value in a case label needs to be a constant expression. That is, the answer to your immediate question is: yes, you can call certain functions in a case label. However, not the ones you tried to call. You can have multiple labels refer to one group of statements, though:
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
do_vowels();
break;
I know this doesn't answer your question per se, but you might try coding it like this....
capitalcount += isCapital(x);
vowelcount += isVowel(x);
The boolean return type of the isXXX() functions would get promoted to an int and added to the counts as either 0 (false) or 1 (true).
First of all: in your desired code isCapital and isVowel should be not functions (and not a function call, definitely), but functors -- because to check a value they have to receive it via parameters...
anyway your code is not possible in C++... but can be simulated with a sequence of pairs of functions: predicate + effect. Predicate have to take some parameter and respond with a boolean. Effect will do smth if predicate is true. To simulate break and fallback to next case (i.e. when no break in a case) effect function also have to return a boolean.
Sample code may look like this:
#include <cctype>
#include <functional>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
{
typedef std::vector<
std::pair<
std::function<bool(char)> // predicate
, std::function<bool()> // effect: return true if `break' required
>
> case_seq_t;
unsigned digits = 0;
unsigned upper = 0;
unsigned lower = 0;
unsigned total = 0;
unsigned other = 0;
case_seq_t switch_seq = {
{
// predicate lambda can be replaced by std::bind
// in this simple case... but need to change param type.
// std::bind(&std::isdigit, std::placeholders::_1)
[](char c) { return std::isdigit(c); }
, [&]() { digits++; return true; }
}
, {
[](char c) { return std::islower(c); }
, [&]() { lower++; return true; }
}
, {
[](char c) { return std::isupper(c); }
, [&]() { upper++; return true; }
}
// `default` case
, {
[](char c) { return true; }
, [&]() { other++; return true; }
}
};
for (int i = 1; i < argc; i++)
for (int pos = 0; argv[i][pos]; pos++)
for (const auto& p : switch_seq)
if (p.first(argv[i][pos]))
if (p.second())
break;
std::cout << "digits=" << digits << std::endl;
std::cout << "upper=" << upper << std::endl;
std::cout << "lower=" << lower << std::endl;
std::cout << "other=" << other << std::endl;
return 0;
}
Not so simple as switch but (IMHO) obvious enough... and maybe, in some real cases, have better flexibility (and probably maintainability) :)