Switch statement c++ - c++

I am writing a code to assign a scoring system to values of a card. I have a member function that takes an int and changes its value based on the scoring system. I can't seem to get it to output anything besides 10 :
int Obj::eval(int b)
{
switch (b)
{
case 0:
b = 11; //automatically assigns ace value of 11
case 1:
b = 2;
case 2:
b = 3;
case 3:
b = 4;
case 4:
b = 5;
case 5:
b = 6;
case 6:
b = 7;
case 7:
b = 8;
case 8:
b = 9;
case 9:
b = 10;
case 10:
b = 10;
case 11:
b = 10;
case 12:
b = 10;
}
return b;
}

Insert break at the end of each case. C's switch is "fall-through": if you don't prevent it, code just keeps executing next line: if b is 0, all the assignments will get executed, in order. break will jump out of the switch.
I.e. your code needs to look like this:
switch (b)
{
case 0:
b = 11; //automatically assigns ace value of 11
break;
case 1:
b = 2;
break;
/* ... */

A switch case should end with a break;. Otherwise there will be a fall through and all the subsequent cases will be executed.
Your code should look something similar to this.
switch(b)
{
case 0:
//bodyhere
break;
case 1:
//bodyhere
break;
}
It's important not to miss the break statements unless you intend to execute the following cases too.

You should always use the break statement after each case because C++ will continue to execute the next case. For example:
switch(b)
{
case 0:
// body
// body
break;
case 1:
// body
// body
break;
case 2:
// body
// body
break;
}
You can also use a default as a last case. However, you don't need a break statement with the default.
switch(b)
{
case 0:
// body
break;
case 1:
// body
break;
case 2:
// body
break;
default:
// body
}

Switch statements in C and C++ have a "feature" called fallthrough, where if you don't actually break out of the cases, execution will just continue through to the next case (thus always resulting in b receiving 10).
Add break statements after each case.
case 0:
b = 11; //automatically assigns ace value of 11
break;
case 1:
b = 2;
break;
case 2:
b = 3;
break;
// etc.

Languages derived from C where control moves to the matching case, and then execution continues or "falls through" to the statements associated with the next case in the source text. Should use a break to avoid it.
case 0:
b = 11;
break;
case 1:
b = 2;
break;
In your case return would be fine too,
case 0:
b = 11;
return b;
case 1:
b = 2;
return b;

In addition to the case fallthrough problem described above, there are more efficient means other than switch to map between values, such as std::map
static map<int, int> myMap = { { 0, 11 }, { 1, 2 }, { 2, 3 }, ... { 11, 10 }, { 12, 10 } };
int Obj::eval(int b)
{
return myMap[b];
}

You need to add a break statement at the end of each branch. Otherwise the flow of control will continue to the next branch.

Related

c++ Do-while loop inside switch-case Statement [duplicate]

I've read the article on Wikipedia on the Duff's device, and I don't get it. I am really interested, but I've read the explanation there a couple of times and I still don't get it how the Duff's device works.
What would a more detailed explanation be?
There are some good explanations elsewhere, but let me give it a try. (This is a lot easier on a whiteboard!) Here's the Wikipedia example with some notations.
Let's say you're copying 20 bytes. The flow control of the program for the first pass is:
int count; // Set to 20
{
int n = (count + 7) / 8; // n is now 3. (The "while" is going
// to be run three times.)
switch (count % 8) { // The remainder is 4 (20 modulo 8) so
// jump to the case 4
case 0: // [skipped]
do { // [skipped]
*to = *from++; // [skipped]
case 7: *to = *from++; // [skipped]
case 6: *to = *from++; // [skipped]
case 5: *to = *from++; // [skipped]
case 4: *to = *from++; // Start here. Copy 1 byte (total 1)
case 3: *to = *from++; // Copy 1 byte (total 2)
case 2: *to = *from++; // Copy 1 byte (total 3)
case 1: *to = *from++; // Copy 1 byte (total 4)
} while (--n > 0); // N = 3 Reduce N by 1, then jump up
// to the "do" if it's still
} // greater than 0 (and it is)
}
Now, start the second pass, we run just the indicated code:
int count; //
{
int n = (count + 7) / 8; //
//
switch (count % 8) { //
//
case 0: //
do { // The while jumps to here.
*to = *from++; // Copy 1 byte (total 5)
case 7: *to = *from++; // Copy 1 byte (total 6)
case 6: *to = *from++; // Copy 1 byte (total 7)
case 5: *to = *from++; // Copy 1 byte (total 8)
case 4: *to = *from++; // Copy 1 byte (total 9)
case 3: *to = *from++; // Copy 1 byte (total 10)
case 2: *to = *from++; // Copy 1 byte (total 11)
case 1: *to = *from++; // Copy 1 byte (total 12)
} while (--n > 0); // N = 2 Reduce N by 1, then jump up
// to the "do" if it's still
} // greater than 0 (and it is)
}
Now, start the third pass:
int count; //
{
int n = (count + 7) / 8; //
//
switch (count % 8) { //
//
case 0: //
do { // The while jumps to here.
*to = *from++; // Copy 1 byte (total 13)
case 7: *to = *from++; // Copy 1 byte (total 14)
case 6: *to = *from++; // Copy 1 byte (total 15)
case 5: *to = *from++; // Copy 1 byte (total 16)
case 4: *to = *from++; // Copy 1 byte (total 17)
case 3: *to = *from++; // Copy 1 byte (total 18)
case 2: *to = *from++; // Copy 1 byte (total 19)
case 1: *to = *from++; // Copy 1 byte (total 20)
} while (--n > 0); // N = 1 Reduce N by 1, then jump up
// to the "do" if it's still
} // greater than 0 (and it's not, so bail)
} // continue here...
20 bytes are now copied.
Note: The original Duff's Device (shown above) copied to an I/O device at the to address. Thus, it wasn't necessary to increment the pointer *to. When copying between two memory buffers you'd need to use *to++.
The explanation in Dr. Dobb's Journal is the best that I found on the topic.
This being my AHA moment:
for (i = 0; i < len; ++i) {
HAL_IO_PORT = *pSource++;
}
becomes:
int n = len / 8;
for (i = 0; i < n; ++i) {
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
HAL_IO_PORT = *pSource++;
}
n = len % 8;
for (i = 0; i < n; ++i) {
HAL_IO_PORT = *pSource++;
}
becomes:
int n = (len + 8 - 1) / 8;
switch (len % 8) {
case 0: do { HAL_IO_PORT = *pSource++;
case 7: HAL_IO_PORT = *pSource++;
case 6: HAL_IO_PORT = *pSource++;
case 5: HAL_IO_PORT = *pSource++;
case 4: HAL_IO_PORT = *pSource++;
case 3: HAL_IO_PORT = *pSource++;
case 2: HAL_IO_PORT = *pSource++;
case 1: HAL_IO_PORT = *pSource++;
} while (--n > 0);
}
There are two key things to Duff's device. First, which I suspect is the easier part to understand, the loop is unrolled. This trades larger code size for more speed by avoiding some of the overhead involved in checking whether the loop is finished and jumping back to the top of the loop. The CPU can run faster when it's executing straight-line code instead of jumping.
The second aspect is the switch statement. It allows the code to jump into the middle of the loop the first time through. The surprising part to most people is that such a thing is allowed. Well, it's allowed. Execution starts at the calculated case label, and then it falls through to each successive assignment statement, just like any other switch statement. After the last case label, execution reaches the bottom of the loop, at which point it jumps back to the top. The top of the loop is inside the switch statement, so the switch is not re-evaluated anymore.
The original loop is unwound eight times, so the number of iterations is divided by eight. If the number of bytes to be copied isn't a multiple of eight, then there are some bytes left over. Most algorithms that copy blocks of bytes at a time will handle the remainder bytes at the end, but Duff's device handles them at the beginning. The function calculates count % 8 for the switch statement to figure what the remainder will be, jumps to the case label for that many bytes, and copies them. Then the loop continues to copy groups of eight bytes.
The point of duffs device is to reduce the number of comparisons done in a tight memcpy implementation.
Suppose you want to copy 'count' bytes from b to a, the straight forward approach is to do the following:
do {
*a = *b++;
} while (--count > 0);
How many times do you need to compare count to see if it's a above 0? 'count' times.
Now, the duff device uses a nasty unintentional side effect of a switch case which allows you to reduce the number of comparisons needed to count / 8.
Now suppose you want to copy 20 bytes using duffs device, how many comparisons would you need? Only 3, since you copy eight bytes at a time except the last first one where you copy just 4.
UPDATED: You don't have to do 8 comparisons/case-in-switch statements, but it's reasonable a trade-off between function size and speed.
When I read it for the first time, I autoformatted it to this
void dsend(char* to, char* from, count) {
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do {
*to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
and I had no idea what was happening.
Maybe not when this question was asked, but now Wikipedia has a very good explanation
The device is valid, legal C by virtue of two attributes in C:
Relaxed specification of the switch statement in the language's definition. At the time of the device's invention this was the first edition of The C Programming Language which requires only that the controlled statement of the switch be a syntactically valid (compound) statement within which case labels can appear prefixing any sub-statement. In conjunction with the fact that, in the absence of a break statement, the flow of control will fall-through from a statement controlled by one case label to that controlled by the next, this means that the code specifies a succession of count copies from sequential source addresses to the memory-mapped output port.
The ability to legally jump into the middle of a loop in C.
1: Duffs device is a particular implementation of loop unrolling. Loop unrolling is an optimisation technique applicable if you have an operation to perform N times in a loop - you can trade program size for speed by executing the loop N/n times and then in the loop inlining (unrolling) the loop code n times e.g. replacing:
for (int i=0; i<N; i++) {
// [The loop code...]
}
with
for (int i=0; i<N/n; i++) {
// [The loop code...]
// [The loop code...]
// [The loop code...]
...
// [The loop code...] // n times!
}
Which works great if N % n == 0 - no need for Duff! If that is not true then you have to handle the remainder - which is a pain.
2: How does Duffs device differ from this standard loop unrolling?
Duffs device is just a clever way of dealing with the remainder loop cycles when N % n != 0. The whole do / while executes N / n number of times as per standard loop unrolling (because the case 0 applies). On the last first run through the loop the case kicks in and we run the loop code the 'remainder' number of times - the remaining runs through the loop run 'normally'.
Though I'm not 100% sure what you're asking for, here goes...
The issue that Duff's device addresses is one of loop unwinding (as you'll no doubt have seen on the Wiki link you posted). What this basically equates to is an optimisation of run-time efficiency, over memory footprint. Duff's device deals with serial copying, rather than just any old problem, but is a classic example of how optimisations can be made by reducing the number of times that a comparison needs to be done in a loop.
As an alternative example, which may make it easier to understand, imagine you have an array of items you wish to loop over, and add 1 to them each time... ordinarily, you might use a for loop, and loop around 100 times. This seems fairly logical and, it is... however, an optimisation can be made by unwinding the loop (obviously not too far... or you may as well just not use the loop).
So a regular for loop:
for(int i = 0; i < 100; i++)
{
myArray[i] += 1;
}
becomes
for(int i = 0; i < 100; i+10)
{
myArray[i] += 1;
myArray[i+1] += 1;
myArray[i+2] += 1;
myArray[i+3] += 1;
myArray[i+4] += 1;
myArray[i+5] += 1;
myArray[i+6] += 1;
myArray[i+7] += 1;
myArray[i+8] += 1;
myArray[i+9] += 1;
}
What Duff's device does is implement this idea, in C, but (as you saw on the Wiki) with serial copies. What you're seeing above, with the unwound example, is 10 comparisons compared to 100 in the original - this amounts to a minor, but possibly significant, optimisation.
Here's a non-detailed explanation which is what I feel to be the crux of Duff's device:
The thing is, C is basically a nice facade for assembly language (PDP-7 assembly to be specific; if you studied that you would see how striking the similarities are). And, in assembly language, you don't really have loops - you have labels and conditional-branch instructions. So the loop is just a part of the overall sequence of instructions with a label and a branch somewhere:
instruction
label1: instruction
instruction
instruction
instruction
jump to label1 if some_condition
and a switch instruction is branching/jumping ahead somewhat:
evaluate expression into register r
compare r with first case value
branch to first case label if equal
compare r with second case value
branch to second case label if equal
etc....
first_case_label:
instruction
instruction
second_case_label:
instruction
instruction
etc...
In assembly it's easily conceivable how to combine these two control structures, and when you think of it that way, their combination in C doesn't seem so weird anymore.
This is an answer I posted to another question about Duff's Device that got some upvaotes before the question was closed as a duplicate. I think it provides a bit of valuable context here on why you should avoid this construct.
"This is Duff's Device. It's a method of unrolling loops that avoids having to add a secondary fix-up loop to deal with times when the number of loop iteration isn't know to be an exact multiple of the unrolling factor.
Since most answers here seem to be generally positive about it I'm going to highlight the downsides.
With this code a compiler is going to struggle to apply any optimization to the loop body. If you just wrote the code as a simple loop a modern compiler should be able to handle the unrolling for you. This way you maintain readability and performance and have some hope of other optimizations being applied to the loop body.
The Wikipedia article referenced by others even says when this 'pattern' was removed from the Xfree86 source code performance actually improved.
This outcome is typical of blindly hand optimizing any code you happen to think might need it. It prevents the compiler from doing its job properly, makes your code less readable and more prone to bugs and typically slows it down. If you were doing things the right way in the first place, i.e. writing simple code, then profiling for bottlenecks, then optimizing, you'd never even think to use something like this. Not with a modern CPU and compiler anyway.
It's fine to understand it, but I'd be surprised if you ever actually use it."
Here is a working example for 64-bit memcpy with Duff's Device:
#include <iostream>
#include <memory>
inline void __memcpy(void* to, const void* from, size_t count)
{
size_t numIter = (count + 56) / 64; // gives the number of iterations; bit shift actually, not division
size_t rest = count & 63; // % 64
size_t rest7 = rest&7;
rest -= rest7;
// Duff's device with zero case handled:
switch (rest)
{
case 0: if (count < 8)
break;
do { *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 56: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 48: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 40: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 32: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 24: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 16: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
case 8: *(((unsigned long long*&)to)++) = *(((unsigned long long*&)from)++);
} while (--numIter > 0);
}
switch (rest7)
{
case 7: *(((unsigned char*)to)+6) = *(((unsigned char*)from)+6);
case 6: *(((unsigned short*)to)+2) = *(((unsigned short*)from)+2); goto case4;
case 5: *(((unsigned char*)to)+4) = *(((unsigned char*)from)+4);
case 4: case4: *((unsigned long*)to) = *((unsigned long*)from); break;
case 3: *(((unsigned char*)to)+2) = *(((unsigned char*)from)+2);
case 2: *((unsigned short*)to) = *((unsigned short*)from); break;
case 1: *((unsigned char*)to) = *((unsigned char*)from);
}
}
void main()
{
static const size_t NUM = 1024;
std::unique_ptr<char[]> str1(new char[NUM+1]);
std::unique_ptr<char[]> str2(new char[NUM+1]);
for (size_t i = 0 ; i < NUM ; ++ i)
{
size_t idx = (i % 62);
if (idx < 26)
str1[i] = 'a' + idx;
else
if (idx < 52)
str1[i] = 'A' + idx - 26;
else
str1[i] = '0' + idx - 52;
}
for (size_t i = 0 ; i < NUM ; ++ i)
{
memset(str2.get(), ' ', NUM);
__memcpy(str2.get(), str1.get(), i);
if (memcmp(str1.get(), str2.get(), i) || str2[i] != ' ')
{
std::cout << "Test failed for i=" << i;
}
}
return;
}
It handles zero-length case (in original Duff's Device there is assumption num>0).
Function main() contains simple test cases for __memcpy.
Just experimenting, found another variant getting along without interleaving switch statement and do-while-loop:
int n = (count + 1) / 8;
switch (count % 8)
{
LOOP:
case 0:
if(n-- == 0)
break;
putchar('.');
case 7:
putchar('.');
case 6:
putchar('.');
case 5:
putchar('.');
case 4:
putchar('.');
case 3:
putchar('.');
case 2:
putchar('.');
case 1:
putchar('.');
default:
goto LOOP;
}
Technically, the goto still implements a loop, but this variant might be slightly more readable.

How to do a if condition in a switch statement in c++

I have this code:
#include <iostream>
using namespace std;
int main() {
int square; char state;
cout<<"Write a numbber"; cin>>square;
square *= square;
cout<<square;
switch(square) {
case 1: state = 'h';
case 3: state = 'm';
case 7: state = 'j';
case (square > 10): state = 'u'; // I try this, but not works
}
return 0;
}
I would like to know how a condition is made inside a switch, in c ++.
The expression following case must be a compile time constant. Hence, you may not use what you are trying.
Change that to default: and then use if.
default:
if (square > 10)
state = 'u';
If you have lots of items you should use a switch. If not, if else is better.
If a switch contains more than five items, it's implemented using a lookup table or a hash list. This means that all items get the same access time, compared to a list of if:s where the last item takes much more time to reach as it has to evaluate every previous condition first.
If you want to use condition or combine some:
switch(square) {
case 1: state = 'h'; break;
case 3: state = 'm';break;
case 7: state = 'j'; break;
case 8:
case 9: state = 'u';
case 10: state = 'z';break;
default: state = 'd';
}
Case 8, 9, 10 will be combined if the square is 8.
If you don't have a break at the end of a case region, control passes along to the next case label.

how does this switch block executes?

#include<bits/stdc++.h>
using namespace std;
void show(int errorCause)
{
switch(errorCause)
{
case 1:
{
cout<<"in 1\n";
break;
}
case 2: break;
case 3:
{
cout<<"in 3\n";
break;
case 4:
{
cout<<"in 4\n";
case 5: cout<<"in 5\n";
break;
}
}
break;
default:
{
cout<<"in deafult\n";
break;
}
}
return;
}
int main()
{
show(5);
return 0;
}
I used this sample of code and I could not figure out its flow.According to me it should match the default condition as the errorCause does not match anything,but its output is:
in 5
I don't understand why it is not going to default condition?
Here is my build environment details:
compiler:
g++ version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
System:
Ubuntu 14.04(64-bit)
You pass 5, why should the switch statement not go into 'case 5'?
To make it clear: Remove all these curly braces inside the switch-block, none of them is necessary. The re-align and format the code, then it should be clear.
case/default labels for a switch statement may appear anywhere within that switch statement, except within a nested switch statement.
A famous example of this usage is Duff's device for unrolling loops:
void copy(unsigned char *to, const unsigned char *from, size_t count)
{
size_t n;
if (!count)
return;
n = (count + 7) / 8;
switch (count % 8) {
case 0:
do {
*to++ = *from++;
case 1:
*to++ = *from++;
case 2:
*to++ = *from++;
case 3:
*to++ = *from++;
case 4:
*to++ = *from++;
case 5:
*to++ = *from++;
case 6:
*to++ = *from++;
case 7:
*to++ = *from++;
case 1:
} while (--n > 0);
}
}
(adapted from the original).
At first glance, that doesn't make any sense (and it is somewhat redundant if you allow the compiler to unroll loops for you), but it illustrates that case labels can be placed more or less where you like within the switch statement.
First, don't write code like that. <g>
Second, the reason that it gets to case 5: is simply that there's a case 5: inside the switch statement. It doesn't matter that it's nested inside two levels of curly braces; it's just a label for the code to jump to. It doesn't have to be at the outer level of the switch statement.
It's because actually the switch statement evaluation is "relaxed", so the braces do not matter there. Only case matters, but you can jump right into the middle of a scope by the case (or even to the middle of a loop, see Duff's device).
because the value you passed is 5 , which exactly matches with the switch case parameter.
case 5: cout<<"in 5\n";
break;
if you want to get the default statement then modify the main function as shown below :
int main()
{
show(6);
return 0;
}
hope this helps.

Need help making my switch case look nicer

So basically my switch case works but my professor says there are too many returns and "use a variable result, then return it at the end!"
so here is my code
int getMonthValue(){
switch(month){
case(1): //January
if(isLeapYear(year) == true)
return 6;
else
return 0;
case(2): // February
if(isLeapYear(year) == true)
return 2;
else
return 3;
case(3): //March
return 3;
case(4): //April
return 6;
case(5): //May
return 1;
case(6): //June
return 4;
case(7): //July
return 6;
case(8): //August
return 2;
case(9): //September
return 5;
case(10): //October
return 0;
case(11): //November
return 3;
case(12): //December
return 5;}
};
I dont see anything wrong with it, I am sure it could be written better. Would someone be able to show me a way to either format this in a more user friendly way? My professor also wanted me to use breaks in the switch instead, not sure why to use the break over return.
This is not good idea to use logical operators in your case. Use a array! This code is very well understood and it is very fast. And it is very easy to change the return value:
unsigned getMonthValue(unsigned month, unsigned year) {
const static unsigned ans[2][12] = {
// Jan F M A M J J A S O N Dec
{0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 } //normal year
, {6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 } //leap year
};
assert(month <= 12);
assert(month >= 1);
const size_t month_index = month - 1;
const size_t leap = isLeapYear(year) ? 1 : 0;
return ans[leap][month_index];
}
UPDATE
There is very useful link about this technic - Lookup_table. Thanks to Schwern!
Try this
int getMonthValue(int month, int year){
map<int,int> staticAnswers;
staticAnswers[3] = 3;
staticAnswers[4] = 6;
staticAnswers[5] = 1;
staticAnswers[6] = 4;
staticAnswers[7] = 6;
staticAnswers[8] = 2;
staticAnswers[9] = 5;
staticAnswers[10] = 0;
staticAnswers[11] = 3;
staticAnswers[12] = 5;
switch(month){
case(1): //January
if(isLeapYear(year) == true)
return 6;
else
return 0;
case(2): // February
if(isLeapYear(year) == true)
return 2;
else
return 3;
default:
return staticAnswers[month];
};
Here is how I would write it:
int
getMonthValue (int month, int year)
{
switch(month)
{
case 1: // January
if (isLeapYear(year))
return 6; // explanation here of why 6 is the right value
return 0;
case 2: // February
if (isLeapYear(year))
return 2; // explain why 2 is the right value
return 3;
case 3: return 3; // March
case 4: return 6; // April
case 5: return 1; // May
case 6: return 4; // June
case 7: return 6; // July
case 8: return 2; // August
case 9: return 5; // September
case 10: return 0; // October
case 11: return 3; // November
case 12: return 5; // December
}
}
I know many inexperienced programmers would object to the statements not being consistent. However—written this way—the statement structure exactly follows the logic. That is, the lexical structure reveals the logic.
A good thing about switch statement is that you are allowed to fall-through case statements, so this is allowed in C++:
switch (month) {
case 4:
case 7:
return 6;
case 9:
case 12:
return 5;
Which should reduce the amount of return statements but will change the readable order.
Another option, since you are checking for all values in range [1-12], would be to use an array, eg:
static const int values[] = { 3, 6, 1 ... };
if (month < 3) {
/* leap year check */
}
else
return values[month - 3]; // we subtract 3 to start from March
But this in the end should be mostly personal preference, so the suggestion given by the professor sounds like just something to nag you.
Your professor is strictly enforcing the "Single Entry, Single Exit" (SESE) rule of Structured Programming. All inputs come in as arguments. All output is via a single return statement at the end. No surprise returns in the middle of the routine. No globals. Minimal side effects. No gotos. It makes code easier to read when you don't have to carefully scan it for returns or calling gotos in the middle of a function.
This is a good rule of thumb. And at the time this was conceived, in the 1970s, this was a radical idea. Now it's just how you do things.
The problem, like many style rules, is when you strictly enforce the rule without considering why the rule exists; you can wind up with the opposite effect. Some of the answers here have illustrated that nicely. Style rules are necessarily simplified versions of reality and enumerating all the edge cases and exceptions is difficult. Gotta allow some wiggle room.
For a small routine like yours that does one very clear thing, fits on one page, and is one easy to read switch statement... just do multiple returns like you're doing. Storing a return value for the end would make it longer and more complicated defeating the point of the rule. And you avoid forgetting a break, a very common C pitfall.
The other good reason to violate SESE is early exit. Structured programming says to do this:
int some_function(int arg) {
int ret;
if( arg < 0 ) {
ret = arg;
}
else {
this is the real
meat and potatoes
of the function
and because of
that one simple
condition at the
top it all
is indented an
extra level
adding complexity
to the whole
function
ret = whatever;
}
return ret;
}
Every level of nesting adds complexity. Early exit avoids this unnecessary nesting by getting the simple cases out of the way at the top.
int some_function(int arg) {
if( arg < 0 ) {
return arg;
}
this is the real
meat and potatoes
of the function
which doesn't
have to be indented
an extra level
since we dealt with
all the simple cases
at the top
return whatever;
}
The extra return at the start doesn't significantly add complexity because it's in a predictable spot. It's only surprise returns in the middle of a large function that are a problem.
The other side of this is minuscule style arguments like this can distract from real problems. Your code has two much bigger problems, and I hope your prof called you on them.
Pass values into functions, don't use globals.
Your function takes no arguments. Instead month and year are globals. This is very bad style. It makes your program difficult to understand because anything can potentially effect anything. Instead, pass them in.
int getMonthValue( int month, int year ) {
...
}
Check your bounds.
The second problem is your function has no bounds checking. What if month is 0? 13? -50? 20398? It will fall through the switch statement and out the bottom of the function. The compiler should have warned you about this.
test.c:48:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
To solve this, unless you can think of a good reason not to, always put a default clause on switch.
switch(month) {
...all your regular cases...
default:
fprintf(stderr, "Month %d is out of range.\n", month);
exit(1);
}
Your professor is right, don't worry its all in the learning process
Try something like this:
int result = -1;
switch(month){
case 1: //January
if(isLeapYear(year) == true)
result = 6;
else
result = 0;
break;
case 2: // February
if(isLeapYear(year) == true)
result = 2;
else
result = 3;
break;
case 3: //March
result = 3;
break;
case 4: //April
result = 6;
break;
case 5: //May
result = 1;
break;
case 6: //June
result = 4;
break;
case 7: //July
result = 6;
break;
case 8 : //August
result = 2;
break;
case 9: //September
result = 5;
break;
case 10: //October
result = 0;
break;
case 11: //November
result = 3;
break;
case 12: //December
result = 5;
break;
}
return result;
Also don't use brackets in your cases it doesnt look clean at all.
I sometimes also choose to use brackets in my cases "{" and "}" although in this example its probably more appropiate not to. Weather or not using brackets is the best practice I do not know.
I am refeering to these brackets by the way "{" and "}"
Anyway thats a cleaner case statement, hope it helped.
a possible solution With the ternary operator!:
int getMonthValue()
{
return
month == 3 ? 3 :
month == 4 ? 6 :
month == 5 ? 1 :
month == 6 ? 4 :
month == 7 ? 6 :
month == 8 ? 2 :
month == 9 ? 5 :
month == 10 ? 0 :
month == 11 ? 3 :
month == 12 ? 5 :
month == 1 ? isLeapYear(year) ? 6 : 0 :
month == 2 && isLeapYear(year) ? 2 : 3 ;
}

Control structures inside switch statements

why the code inside the if block executed any way?
switch(v)
{
case a:
break;
...
if(condition)
{
case f:
...
break;
case g:
...
break;
}
...
case z:
...
break;
default:
}
The C++ compiler uses a lookup table or direct branches to the case-statements. Ignoring your the if-statement. Due to the break it is also not reached from case a.
Long answer short you cannot 'turn off' case-statements using this method.
Instead you'd need something like this:
switch(v) {
case a :
break;
//...
case f :
if(condition) {
//...
}
break;
case g :
if(condition) {
//...
}
break
//...
case z :
break;
}
A case label, as the name implies, is an actual label and works very similar to a goto label: the execution thread just jumps to it. It does not matter what structure it is in, unless that structure is another, nested switch statement.
It works the same way as this:
if (v == f)
goto f_label;
if (condition) {
f_label:
// ...
}
The execution thread will jump to the f_label: label regardless of whether condition is true or not. switch labels work the same way.
The case clauses for a switch are quite flexible and you can do some hacks for them. I have seen some people use switch to break out of nested for loops for instance. Still in the example above if v is f or g the switch will just skip the if statement and the code in the case will be executed right after switch.
When program is compiling switch builds some table to jump from one case to another. This jumps somehow ignoring other conditional operations. BTW according to such behavior switch is faster than long if-else blocks.
I think the best answer to how is( inspired from the answer of Nikos C.):
switch(v)
{
case a:
break;
case z:
...
break;
default:
if(condition)
{
switch(v)
{
case f:
...
break;
case g:
...
break;
default:
//former default
}
}
else
//former default
}
Switch jumps to the matched case ignoring all statements in between. You have two ways to accomplish what you intend to do (depending upon the number of cases you have to implement):
Method 1 for more number of cases under the if conditional
if(condition) {
switch(v) {
case f :
....
break;
//...
case g :
....
break;
//...
case z :
break;
}
switch(v) {
case a :
....
break;
//...
}
Method 2 for less cases under the if conditional
switch(v) {
case a :
break;
//...
case f :
if(condition) {
//...
}
break;
case g :
if(condition) {
//...
}
break
//...
case z :
break;
}