According to this book I am readingļ¼
Q What happens if I omit a break in a switch-case statement?
A The break statement enables program execution to exit the switch construct.
Without it, execution continues evaluating the following case statements.
Suppose if I have codes looking like
switch (option}{
case 1:
do A;
case 2:
do B;
default:
do C;
break;
}
Does this mean if I choose case 1, the A and C are done. If I choose case 2, B and C are done. If i choose neither, then only C is done.
if so, what happens if we omit the break after do C.
I assume these are bad programming practice, but I am curious what would happen to get a deeper understanding how it all works. Thanks
You execute everything starting from the selected case up until you see a break or the switch statement ends. So it might be that only C is executed, or B and then C, or A and B and C, but never A and C
If you don't include break in any of case then all the case below will be executed and until it sees break.
And if you don't include break in default then it will cause no effect as there are not any case below this 'Default' case.
And not using break generally considered as a bad practice but some time it may also come handy because of its fall-through nature.For example:
case optionA:
//optionA needs to do its own thing, and also B's thing.
//Fall-through to optionB afterwards.
//Its behaviour is a superset of B's.
case optionB:
// optionB needs to do its own thing
// Its behaviour is a subset of A's.
break;
case optionC:
// optionC is quite independent so it does its own thing.
break;
The break acts like a goto command. Or, as a better example, it is like when using return in a void function. Since it is at the end, it makes no difference whether it is there or not. Although, I do like to include it.
switch (option}{
case 1:
do A;
case 2:
do B;
case 2:
do C;
break;
default:
do C;
}
if your option is 1 it executes everything til it finds the break keyword...
that mean break end the excution of the switch --> case
Output :A then B then C
so it is recommended to put break after each case
like :
switch (option}{
case 1:
do A;
break;
case 2:
do B;
break;
do C;
break;
default:
do D;
}
if your option is 1 the Output will be : just A ...
note: default doesn't need a break;
I've seen in many comments and answers that it's a bad practice to omit break lines. I personally find it very useful in some cases.
Let's just take a very simple example. It's probably not the best one, just take it as an illustration:
- on bad login, you need to log the failed attempt.
- for the third bad attempt, you want to log and do some further stuff (alert admin, block account, ...).
Since the action is the same for first and second try, no need to break between these two and rewrite the same commands a second time.
Now the third time, you want to do other things AND also log. Just do the other things first, then let it run (no break) through the log action of the first and second attempts:
switch (badCount) {
case 3: //only for 3
alertAdmin();
blockAccount();
case 2: //for 2 AND 3
case 1: //for 1 AND 2 and 3
errorLog();
badCount++;
}
Imho, if it was soooo bad practice to have common code for different cases, the C structure would simply NOT allow it.
The key is execution control is transferred to the statement for the matching case.
E.g.
1. switch(x) {
2. case 1:
3. do_step1;
4. case 2:
5. do_step2;
6. default:
7. do_default;
8. }
Treat lines 2, 4, 6, as "Labels" for the goto calls. On x = 1, the control will be transferred to line 3 & execution of line 3, 5 & 7 will occur.
Try yourself - Run the code using ideone available here.
#include <stdio.h>
void doA(int *i){
printf("doA i = %d\n", *i);
*i = 3;
}
void doB(int *i){
printf("doB i = %d\n", *i);
*i = 4;
}
void doC(int *i){
printf("doC i = %d\n", *i);
*i = 5;
}
int main(void) {
int i = 1;
switch(i){
case 1:
doA(&i);
case 2:
doB(&i);
default:
doC(&i);
break;
}
return 0;
}
Output:
doA i = 1
doB i = 3
doC i = 4
Note:
It will execute all the options from the selected case until it sees a break or the switch statement ends. So it might be that only C is executed, or B and then C, or A and B and C, but never A and C
If you change the value of the variable analysed in switch inside the handle function (e.g doA), it does not affect the flow as describe above
Without break statements, each time a match occurs in the switch, the statements for that case and SUBSEQUENT CASES execute until a break statement or the end of the switch is encountered.
Related
I was doing a quiz online based on the C++ switch statement. I came across a question and I have a fair understanding of how switch statements work but this one question made absolutely no sense to me. Can someone please explain?
Why is the answer D and not C?
Is Case 2: the default case or what?
This quiz can be found at: http://www.cprogramming.com/tutorial/quiz/quiz5.html
Here's how this code behaves.
x is equal to zero
so cout<<"Zero"; is executed.
Since there's no break; after it,
the second case is executed: cout<<"Hello World";
And since cout<<"something"; doesn't add a newline after printing, they're printed as a single word.
since there is no break; statements in each case, the code will fall-through from case 0: to case 2:.
In C++ a case will "fall-through" if there is no break statement:
int temperature = 20;
switch(temperature)
{
case 20:
cout << "it's nice and warm";
case 25:
cout << "it's a bit hot";
break;
case 30:
cout << "It's way too hot!";
break;
}
This will print out:
it's nice and warm AND it's a bit hot because there is no break statement.
Since, x=0. It matches the 2nd case i.e. (case 0: cout << "Zero"; ). But there is no break statement to break out of the switch statement, it executes next cases too. If you have other cases its gonna execute and stop only when it find break statement or reaches the end of the switch case.
A simple programm that reads strings, and responds using a switch;
in this do-while loop containing a switch, I am able to run case 1-4 with no issues, but once i hit the default case, the programme simply loops the default case over and over again the code is as follows;
do { switch ( switchstring (entry, input) )
/*the switchstring function is one 1 wrote to convert a given entry(string),
into an input(integer)*/
{
case 1:
//code
repeat = 2;
break;
case 2:
//code
repeat = 2;
break;
case 3:
//code
repeat = 2;
break;
case 4:
//code
repeat = 2;
break;
default:
//code
repeat = 1;
break;}} while(repeat == 1);
the 2nd question is regarding my switchstring() function; is there a way to change the switch function such that it reads;
case (insert string):
i.e. so that I can remove the entire switchstring() function
thanks in advance!
Show us how switchstring (entry, input) works.
The problem you are facing is because, in default you do the following:
repeat = 1;
Which makes while(repeat == 1) always true. And then switchstring (entry, input) always return something that makes your switch block always go the the default case again.
When no case will be true in switch, then it will go in default case of switch and you are specifying repeat=1; in default. After that while condition will be checked and it will be true because repeat is 1, again it will go to do and check condition, your switch function will return something and it will go to default.
To solve 2nd question regarding your switchstring() function, you have to show your code what you are doing in that function, So that i can give you best suggestion.
How to execute all cases in switch statement without duplicating existing in big "all-in-one" case ?
For e.g.
switch(obj.nObjType)
{
case eElephant:
...
break;
case eFoo:
...
break;
case eSeptember:
...
break;
default:
return;
}
I want force executing code for all 3 cases (eElephant, eFoo, eSeptember) like there is no break;, for example in case of nObjType = eAllTypes .
You can't just ignore a break. Rather, restructure your code.
switch(obj.nObjType) {
case eElephant:
pokeElephant();
break;
case eFoo:
barTheFoo();
break;
case eSeptember:
rememberSeptember();
break;
case eAllTypes:
pokeElephant();
barTheFoo();
rememberSeptember();
break;
default:
return;
}
Then use if statements:
if (obj.nObjType == eElephant || obj.nObjType == eAllTypes)
{
// Elephant code
}
if (obj.nObjType == eFoo || obj.nObjType == eAllTypes)
{
// Foo code
}
// etc.
This answer is how it should be done.
However:
I can see, it's hard to find as right solution without generating lots
of code lines. Thanks #TobiMcNamobi, but in my switch there is about
200 of cases, so creating a function for each case is not a good idea.
I think, the best can be (unfortunately) duplicating all cases in a
big one. Because, I suppose, if else is much less efficient then
switch statement ?
With this many cases (what on earth are you working on?) even extracting methods leaves you with 200 extra function calls in the body of your switch statement. This could get harder to maintain quickly.
In this case, I would do the following:
switch(enum_variable)
{
case e_all:
case e_1:
e_1_function();
if(enum_variable != e_all){break;} //**
case e_2:
e_2_function();
if(enum_variable != e_all){break;} //**
//...
default:
break;
}
The lines marked //** will break when not doing all cases. It is quick to implement (can be done with a search and replace of break; which speeds things up for you) and does what you want.
With that said, it's still a pretty terrible way of doing it, but exceptions do sometimes have to be made.
I do however recommend that you do not turn to this as a style to use in the future. You may find that you can do better by re-thinking the workflow of your project, as this will probably allow you to simplify and improve. Of course, we don't know what you are working on, so I can't offer more advice.
If you put your switch statement in a function, and make your obj have a list of flags rather than a flag, you can call the function with the switch statement for each flag in the list. Pseudo:
void dostuff(flag)
switch(flag) {
// ...
}
}
for (auto flag in obj.flags) {
dostuff(flag)
}
Is the following possible in C++?
switch (value) {
case 0:
// code statements
break;
case 1:
case 2:
// code statements for case 1 and case 2
/**insert statement other than break here
that makes the switch statement continue
evaluating case statements rather than
exit the switch**/
case 2:
// code statements specific for case 2
break;
}
I want to know if there is a way to make the switch statement continue evaluating the rest of the cases even after it has hit a matching case. (such as a continue statement in other languages)
How about a simple if?
switch (value)
{
case 0:
// ...
break;
case 1:
case 2:
// common code
if (value == 2)
{
// code specific to "2"
}
break;
case 3:
// ...
}
Once the case label is decided, there is no way to have the switch continue to search for other matching labels. You can continue to process the code for the following label(s) but this doesn't distinguish between the different reasons why a case label was reached. So, no, there is no way to coninue the selection. In fact, duplicate case labels are prohibited in C++.
Yep, just don't put in a break. It will naturally fall down to the other switch statements.
I came across a case-switch piece of code today and was a bit surprised to see how it worked. The code was:
switch (blah)
{
case a:
break;
case b:
break;
case c:
case d:
case e:
{
/* code here */
}
break;
default :
return;
}
To my surprise in the scenario where the variable was c, the path went inside the "code here" segment. I agree there is no break at the end of the c part of the case switch, but I would have imagined it to go through default instead. When you land at a case blah: line, doesn't it check if your current value matches the particular case and only then let you in the specific segment? Otherwise what's the point of having a case?
This is called case fall-through, and is a desirable behavior. It allows you to share code between cases.
An example of how to use case fall-through behavior:
switch(blah)
{
case a:
function1();
case b:
function2();
case c:
function3();
break;
default:
break;
}
If you enter the switch when blah == a, then you will execute function1(), function2(), and function3().
If you don't want to have this behavior, you can opt out of it by including break statements.
switch(blah)
{
case a:
function1();
break;
case b:
function2();
break;
case c:
function3();
break;
default:
break;
}
The way a switch statement works is that it will (more or less) execute a goto to jump to your case label, and keep running from that point. When the execution hits a break, it leaves the switch block.
That is the correct behavior, and it is referred to as "falling through". This lets you have multiple cases handled by the same code. In advanced situations, you may want to perform some code in one case, then fall through to another case.
Contrived example:
switch(command)
{
case CMD_SAVEAS:
{
this->PromptForFilename();
} // DO NOT BREAK, we still want to save
case CMD_SAVE:
{
this->Save();
} break;
case CMD_CLOSE:
{
this->Close();
} break;
default:
break;
}
This is called a fall-through.
It is exactly doing what you are seeing: several cases is going to execute same piece of code.
It is also convenient in doing extra processing for certain case, and some shared logic:
// psuedo code:
void stopServer() {
switch (serverStatus)
case STARTING:
{
extraCleanUpForStartingServer();
// fall-thru
}
case STARTED:
{
deallocateResources();
serverStatus = STOPPED;
break;
}
case STOPPING:
case STOPPED:
default:
// ignored
break;
}
This is a typical use of fall-through in switch-case. In case of STARTING and STARTED, we need to do deallocateResources and change the status to STOPPED, but STARTING need some extra cleanup. By the above way, you can clearly present the 'common logic' plus extra logic in STARTING.
STOPPED, STOPPING and default are similar, all of them fall thru to default logic (which is ignoring).
It is not always a good way to code like this but if it is well used it can present the logic better.
Luckily for us, C++ doesn't depend on your imagination :-)
Think of the switch labels as "goto" labels, and the switch(blah) simply "goes to" the corresponding label, and then the code just flows from there.
Actually the switch statement works the way you observed. It is designed so that you can combine several cases together until a break is encountered and it acts something like a sieve.
Here is a real-world example from one of my projects:
struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
struct keystore_entry *e;
e = rsd_malloc(rsd, sizeof(struct keystore_entry));
if ( !e )
return NULL;
e->type = type;
switch (e->type) {
case KE_DOUBLE:
memcpy(&e->dblval, value, sizeof(double));
break;
case KE_INTEGER:
memcpy(&e->intval, value, sizeof(int));
break;
/* NOTICE HERE */
case KE_STRING:
if ( size == 0 ) {
/* calculate the size if it's zero */
size = strlen((const char *)value);
}
case KE_VOIDPTR:
e->ptr = rsd_malloc(rsd, size);
e->size = size;
memcpy(e->ptr, value, size);
break;
/* TO HERE */
default:
return NULL;
}
return e;
}
The code for KE_STRING and KE_VOIDPTR cases is identical except for the calculation of size in case of string.