Search

7.4 — Switch statement basics

Although it is possible to chain many if-else statements together, this is both difficult to read and inefficient. Consider the following program:

While this example isn’t too complex, x is evaluated three times, and the reader has to be sure that it is x being evaluated each time (not some other variable).

Because testing a variable or expression for equality against a set of different values is common, C++ provides an alternative conditional statement called a switch statement that is specialized for this purpose. Here is the same program as above using a switch:

The idea behind a switch statement is simple: an expression (sometimes called the condition) is evaluated to produce a value. If the expression’s value is equal to the value after any of the case labels, the statements after the matching case label are executed. If no matching value can be found and a default label exists, the statements after the default label are executed instead.

Compared to the original if statement, the switch statement has the advantage of only evaluating the expression once (making it more efficient), and the switch statement also makes it clearer to the reader that it is the same expression being tested for equality in each case.

Best practice

Prefer switch statements over if-else chains when there is a choice.

Let’s examine each of these concepts in more detail.

Starting a switch

We start a switch statement by using the switch keyword, followed by parenthesis with the conditional expression that we would like to evaluate inside. Often the expression is just a single variable, but it can be any valid expression.

The one restriction is that the condition must evaluate to an integral type (see lesson 4.1 -- Introduction to fundamental data types if you need a reminder which fundamental types are considered integral types). Non-fundamental types that are convertible to an integer (e.g. enumerated types and some classes) are also valid. Expressions that evaluate to floating point types, strings, and other non-integral types may not be used here.

Following the conditional expression, we declare a block. Inside the block, we use labels to define all of the values we want to test for equality. There are two kinds of labels.

Case labels

The first kind of label is the case label, which is declared using the case keyword and followed by a constant expression. The constant expression must either match the type of the condition or must be convertible to that type.

If the value of the conditional expression equals the expression after a case label, execution begins at the first statement after that case label and then continues sequentially.

Here’s an example of the condition matching a case label:

This code prints:

Two

In the above program, x is evaluated to produce value 2. Because there is a case label with value 2, execution jumps to the statement underneath that matching case label. The program prints Two, and then the return statement is exited, which returns back to the caller.

There is no practical limit to the number of case labels you can have, but all case labels in a switch must be unique. That is, you can not do this:

The default label

The second kind of label is the default label (often called the default case), which is declared using the default keyword. If the conditional expression does not match any case label and a default label exists, execution begins at the first statement after the default label.

Here’s an example of the condition matching the default label:

This code prints:

Unknown

The default label is optional, and there can only be one default label per switch statement. By convention, the default case is placed last in the switch block.

Best practice

Place the default case last in the switch block.

Taking a break

In the above examples, we used return statements to stop execution of the statements after our labels. However, this also exits the entire function.

A break statement (declared using the break keyword) tells the compiler that we are done executing statements within the switch, and that execution should continue with the statement after the end of the switch block. This allows us to exit a switch statement without exiting the entire function.

Here’s a slightly modified example rewritten using break instead of return:

The above example prints:

Three Ah-Ah-Ah!

Best practice

Each set of statements underneath a label should end in a break statement or a return statement.

So what happens if you don’t end a set of statements under a label with a break or return? We’ll explore that topic, and others, in the next lesson.


7.5 -- Switch fallthrough and scoping
Index
7.3 -- Common if statement problems

446 comments to 7.4 — Switch statement basics

  • Rob G.

    Hi Alex, exercise well done.

    I took the opportunity to static_cast the char and used switch statements with each ascii value. What a hoot.
    Overall, I am jealous I think your example is more elegant and simple. Is a prime opportunity to use static cast. Also, struct may be more efficient.

  • I took your example program and ran it on Visual Studio 2013:

    #include "stdafx.h"
    #include <iostream>

    bool isDigit(char c)
    {
        switch (c)
        {
        case '0': // if c is 0
        case '1': // or if c is 1
        case '2': // or if c is 2
        case '3': // or if c is 3
        case '4': // or if c is 4
        case '5': // or if c is 5
        case '6': // or if c is 6
        case '7': // or if c is 7
        case '8': // or if c is 8
        case '9': // or if c is 9
            return true; // then return true
        default:
            return false;
        }
    }

    I get the following error with this program and your other switch examples:

    error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup

    Is there a setting I need to change or do I need to include another library to resolve this problem?

  • Aryan

    Hey Alex!
    In the first solution you put return 0 inside the switch block rather than outside it. Does it make a difference. Because I think in your example the calculate() function does not return a value.

    • Alex

      In this case, it doesn't make a difference. Since there's a default case, we're guaranteed that _some_ case will execute. And since all cases have a return statement, we're guaranteed to hit a return statement before the switch executes.

      You could put a return statement after the switch just for safety, but for now it would never get executed.

  • Mr D

    Ah, ok, so after case 2 is matched, the compiler doesn't look for (or care about) any more  "case" statements and just sees the

    parts and executes that?

  • Mr D

    Hi Alex,

    Could you explain why, in the snippet below, we get a print out of:
    2, 3, 4, 5 ?

    After matching case 2, why does it go on to match cases 3, 4 and 5, when in fact they don't match?!

    • Alex

      That's just the way they were designed. Switches start execution at the first matching case, and then keep executing until a break, return, goto, exit statement, or end of the switch is reached.

      You can see where this is useful in the isDigit() example above. More often than not, it's a pain.

      If I were designing a switch statement for C++, I would have designed it the other way around: cases would implicitly break at the next case statement unless an explicit "fall-through" keyword was provided. But nobody asked me. :P

      • AS

        I guess the way switch works now is designed to support range of tests as below:

        Otherwise it would not be possible to use multiple case’s with one execution.

  • Ed

    So im going to do two things. The first is a question on your solution. In the SWITCH function in the getAnimalName(), you dont have any BREAKs. Why doesnt this cause fall-through?

    the second is, I got my code to work (taking me a while to think things through logically), mine is mostly the same, however I do the following:

    My printNumberofLegs() is also a std::string instead of a void. So my questions is, would this be considered a sloppy way of doing it, and would instead of defining pig and chicken, should I just have used Animal::pig and Animal::chicken in the std::cout areas?

    Thanks.

    PS: I saw that you just had your ANIMAL_PIG and such and it took me forever to realize you were using a ENUM not ENUM CLASS and thats why yours looked different.

  • I am not sure but I think the Heading "Default labels" should be "The default label" because each switch can  contain only one default label.

  • techsavvy....aye

    Will you give an example of operating this snippet,

    Thanks in advance.

    • Alex

      Sorry, I'm not clear on what you mean. Are you asking for this snippet to be put inside a program that you can run?

      If so, by this point you should be able to do that yourself. This snippet is self-contained, so you should be able to toss it into an empty main() function and run the resulting program.

  • Shivam Tripathi

    got it...thnx once again Alex...:)

  • Shivam Tripathi

    @ If a case needs to define a new variable, you can do so by putting it inside a block underneath the case:

    switch (1)
    {
        case 1:
        { // note addition of block here
            int x = 4; // now legal
            std::cout << x;
            break;
        }
        default:
            std::cout << "default case" << std::endl;
            break;
    }

    Correct me if m wrong...but i think that the "break" should come outside of the block...

  • splotz

    How could we change Quiz 2 to where the user inputs the animal name ?

    • Alex

      Dealing with text is complicated.

      Probably the easiest way would be to add code to do the following:
      * #include <string>
      * Instantiate a variable of type std::string in main().
      * Use std::cin to read in a string from the user
      * Write a function that takes the string as a parameter and returns the appropriate matching enum
      * Ensure your function works with different capitalizations of the string.

  • cpplx

    quiz1... works properly but prints extra nonsense data in the error case. i object :)

  • devkkp

    THIS ERROR IS SEEN WHEN I COMPILED A PROGRAM ! WHAT DOES IT MEAN?

    1>c:\users\ganeshji\documents\visual studio 2010\projects\switch statements\switch statements\switch statements.cpp(61): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?

  • C++ newbie

    Hey there,

    in my code I had something like this in main:

  • Todd

    Typo:

    "Write a function called Calculate()" (in your solution, you write a function called 'calculate()', which is correct with first letter lowercase)

    Quiz 1 solution typos:

    Above, "Calculate():" should be "calculate():"

    Your main() function doesn't have a 'return' statement.

    Quiz 2 solution typos:

    Above, instead of " walks on ", your quiz question requires us to write " has "

    Above, you should say "printNumberofLegs()", not "getNumberOfLegs()".
    Also above, 'animal' (of data type "Animal") cannot be printed here using std::cout (compiler error occurs). Maybe use stat_cast<int>(animal)

  • Jatn

    I ran the following code for question in code blocks and compiler showed me lots of messages and 2 errors

    The errors were like this
    C:\Documents and Settings\ADMIN\Desktop\Family\C++ Files\problems\main.cpp|68|error: no match for 'operator<<' in 'std::operator<< <std::char_traits<char> >((* & std::operator<< <char, std::char_traits<char>, std::allocator<char> >((* & std::operator<< <std::char_traits<char> >((* & std::cout), ((const char*)"A "))), (*(const std::basic_string<char>*)(& getAnimalName(Animal)())))), ((const char*)" has ")) << printNumberOfLegs(Cat)'|

    and the other one is

    C:\Documents and Settings\ADMIN\Desktop\Family\C++ Files\problems\main.cpp|69|error: no match for 'operator<<' in 'std::operator<< <std::char_traits<char> >((* & std::operator<< <char, std::char_traits<char>, std::allocator<char> >((* & std::operator<< <std::char_traits<char> >((* & std::cout), ((const char*)"A "))), (*(const std::basic_string<char>*)(& getAnimalName(Animal)())))), ((const char*)" has ")) << printNumberOfLegs(Chicken)'|

    Can anybody help....

    • Alex

      printNumberOfLegs() returns void, but you're trying to send that void result into cout. You'll need to break line 68 and 69 up like this:

      Or change printNumberOfLegs() to return a value.

  • Aacon

  • Snowman

    So I decided to take it a step further. This program takes a calculation as one long string input, can have multiple operators but will not calculate using BODMAS but rather in order of appearance.

    Eg. user enters 4+7*2-1
    Answer is: 21 (4+7=11, 11*2=22, 22-1=21)

    Just made it as a challenge. Used a C++11 command called stof (string to float). Program ignores whitespace.

    • Snowman

      Correction above, line 33 should be:

      Won't cause an error, but is wrong none the less

  • Andy

    I have used every single thing that I learned in previous lessons to complete the quiz.
    Heck, I even used a boolean to check whether the user had already filled in a first operand and it worked.
    Now this is what motivates me to keep learning this awesome language!

    What I didn't understand is why this gave me an error:

    I had to do this instead:

    If anyone could give me some further explanation on this, that would be highly appreciated!
    Note: This was inside a switch statement under main().

    Thank you for the lessons!

    Sincerely
    Andy

    • Snowman

      Hi, if you still wish for someone to help out, please post the full code. I cannot help with the snippet your provided.

      EDIT

      Ok, maybe I can. Functions return a value, switch statements are just complex ifs and ifs do not return a value but rather preform commands. Therefore, the return is not correct because it is trying to send a value nowhere, but the second snippet of cout, break preforms the cout then exits the switch as intended.

      tl;dr: switch statements cannot return a value in main, only in a function with a return type.

    • Alex

      cout prints something to the screen. What would it mean to return this to another function?

  • What is the differtence between using RETURN or BREAK in the Switch CASE instruction?

    • Alex

      return exits the entire function that the switch is inside of and returns a value to the caller.
      break exits only the switch, and code execution continues below the switch statement.

  • sush tiwari

    I Love this tutorial!!!!!!!!!! Alex u did a great JOB!!!!!!!!!

    which one is faster switch or if else? why?

    • Alex

      Switch, because of the way it's implemented internally.

      A switch uses a jump table to quickly determine which set of statements to execute, whereas an if-else chain has to do one comparison per if-else condition.

      However, the downside of switches is that they are somewhat limited in what they can do.

  • DrSuse

    Completed (working) code:

  • tadepalli.vinay

    Can someone tell me why switch-case-default statements cannot use floating point values. I mean, i want the reason behind it. As I understand, SWITCH statements can make your program faster compared to the IF-ELSE ladder since it generates a jump table in the compilation without need to wait during execution time. But can't it be done with floating-point values as well?
    Good Reasoning is required.

  • Jesper

    Hi Alex

    I want to say that i love these tutorials you've made. I've been away from
    c++ for some years and I needed a brush-up and this is just perfect. Great job!!
    I have something to add to this section on the switch-case construct though.
    The real reason why there is two ways to achieve the same thing i.e. if-elseif-else and switch-case
    is because of execution-speed. if-elseif-else will always execute in linear time while switch-case
    is implemented using a jump-table meaning it will execute in constant time. Though the jump-table
    will only be used if the case-values are not spread out too far, because that would make the
    jump-table too big.
    So if it is possible you should always use switch-case and keep switch-values in the low range.

  • Denis

    Is it necessary to use the break statement following the default code? For example -

    It seems rather redundant. Is there a practical purpose for doing so?

    • Alex

      It's not redundant, it's superfluous. :)

      The only reason that you'd need to include a break at the end of your default case is if the default case wasn't the last case. In that case, anything that matched the default case would fall-through to the cases below.

  • Anthony

    This code does not give the expected results, any clue why? It compiles, it just doesn't do what it should do.

    • Anthony

      I updated it with this code, but there has to be a better way, lol

    • Helvetica Standard

      6 years late so the guy I'm replying to is probably a veteran programmer now, but I modified his code a bit to make it work - both for my own pratice, and because I found the idea of letting the user enter "add" "Subtract" etc to select the operator in the program interesting.

  • siku

    My car class doesn't compile. Compiler gives me error "C2051: case expression not constant". Although I have defined a constant integral variable ( const int up = (int) mUpKey). I worked around this problem using if else statements but I am still interested to solve it by using switch statement. Can you explain why switch doesn't work because I have a constant expression after case.

    Here is the example code:

    class Car
    {
    private:
    char mUpKey;

    public:
    Car(char upKey):mUpKey(upKey){};
    bool getKeyPress( const char c)
    {
    const int up = static_cast(mUpKey);
    switch(c)
    {
    case up:
    //move(0, 1);
    return true;
    }

    return false;
    }
    };

    • Aah, you've run across a very interesting case here. Case statements have to be statements that are essentially compile-time constants. So something like this will work:

      This works because up is a constant at compile time.

      However, in your case, your value of up is dependent upon the value of mUpKey, which can vary depending on the instance of Car. So even though your value of up has been made const, it's not a compile-time constant.

      • siku

        Thanks for your reply. In that case I would not change my code to use switch statement because it would not allow users to set one's keys later.

  • Jeff

    In a real-world application, where we are concerned with the possible perils of integer division, would it be better to have Calculate() return a double? And, if so, does the following work:

    Will the other cases (e.g., addition of two integers) automatically convert the integer sum to a double return value without the compiler complaining?

    • Whether it's more appropriate to return an int or a double depends entirely on your needs. For some tasks, integer division might be exactly what you want. Others, maybe not. If your function is going to return a double, you might want to modify it to take double parameters as well so you can do floating point addition, subtraction, and multiplication.

      I believe your case would work as you intend. And yes, an integer return value will be implicitly converted to a double if the function has been declared to return a double.

  • Allen01

    Thanks for the examples. I have another question: What are the rules for adding a semi-colon to the end of a block? If I remove the semi-colon from the end of the enum Colors block, it will not compile.

    • As far as I can tell, all statements should be terminated by a semicolon, EXCEPT for compound statements (blocks).

      A declaration is considered a statement, and thus should be terminated by a semicolon. An enum is a declaration so it needs to be terminated with a semicolon. Same with a class declaration. The statements inside a switch are considered compound statements, so they do not need a terminating semicolon.

  • Allen01

    Alex, could you show one or two programs from the examples above worked fully? for example, could you show how the code below might evaluate in the main function. Thanks. Also, shouldn't the symbolic constant enumerators in the "enum Colors" block end with a ',' instead of a ';'?

    enum Colors
    {
        COLOR_BLACK;
        COLOR_WHITE;
        COLOR_RED;
        COLOR_GREEN;
        COLOR_BLUE;
    };
    
    
    
    void PrintColor(Colors eColor)
    {
        using namespace std;
        switch (eColor)
        {
            case COLOR_BLACK:
                cout << "Black";
                break;
            case COLOR_WHITE:
                cout << "White";
                break;
            case COLOR_RED:
                cout << "Red";
                break;
            case COLOR_GREEN:
                cout << "Green";
                break;
            case COLOR_BLUE:
                cout << "Blue";
                break;
            default:
                cout << "Unknown";
                break;
        }
    }
    
    int Main()
    {
    
    // Please show how the code in the above blocks might evaluate.
    
    }
    
    
    • You're right, the enums should be separated by commas, not semicolons. I fixed the example.

      Here's a piece of sample code:

      This produces the result:

      Not the most useful example, perhaps.

      Here's another example:

      Sample output:

      • Aacon

        Hi,Alex~
        Could you please tell me how to post my answer with    c o d e  f o n t ? ( line-by-line like you.)
        Thank you so much.

      • Nurlan

        Hello, Alex!
        I did not get this program.
        Can you clarify this question? Why this below shown program shows true even the number does not exist in switch statement? But it gives Warning in C++11 compiler. Thanks in advance.
        bool isDigit(char c)
        {
            switch (c)
            {
                case '0': // if c is 0
                case '1': // or if c is 1
                case '2': // or if c is 2
                case '3': // or if c is 3
                case '4': // or if c is 4
                case '5': // or if c is 5
                case '6': // or if c is 6
                case '7': // or if c is 7
                case '8': // or if c is 8
                case '9': // or if c is 9
                    return true; // then return true
                default:
                    return false;
            }
        }
        int main()
        {
            
            std::cout<<isDigit('111');
            return 0;
        }

        • Alex

          '111' is not a valid single character. If you try to put multiple characters in single quotes, C++ treats this as a multicharacter literal. A multicharacter literal has type int and implementation-defined value. So, basically, you're passing an implementation-defined integer to a character parameter. In your case, it sounds like that's being mapped to '1', which causes the function to return true. However, this isn't guaranteed to work on all compilers.

          In short, don't put multiple characters inside single quotes (except for escape sequences).

Leave a Comment

Put all code inside code tags: [code]your code here[/code]