Search

5.3 — Switch statements

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

Because doing if-else chains on a single variable testing for equality is so common, C++ provides an alternative conditional branching operator called a switch. Here is the same program as above in switch form:

The overall idea behind switch statements is simple: the switch expression is evaluated to produce a value, and each case label is tested against this value for equality. If a case label matches, the statements after the case label are executed. If no case label matches the switch expression, the statements after the default label are executed (if it exists).

Because of the way they are implemented, switch statements are typically more efficient than if-else chains.

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 the expression that we would like to evaluate. Typically this expression is just a single variable, but it can be something more complex like nX + 2 or nX - nY. The one restriction on this expression is that it must evaluate to an integral type (that is, char, short, int, long, long long, or enum). Floating point variables and other non-integral types may not be used here.

Following the switch 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. A constant expression is one that evaluates to a constant value -- in other words, either a literal (such as 5), an enum (such as COLOR_RED), or a constant variable (such as x, when x has been defined as a const int).

The constant expression following the case label is tested for equality against the expression following the switch keyword. If they match, the code under the case label is executed.

It is worth noting that all case label expressions must evaluate to a unique value. That is, you can not do this:

It is possible to have multiple case labels refer to the same statements. The following function uses multiple cases to test if the ‘c’ parameter is an ASCII digit.

In the case where c is an ASCII digit, the first statement after the matching case statement is executed, which is “return true”.

The default label

The second kind of label is the default label (often called the “default case”), which is declared using the default keyword. The code under this label gets executed if none of the cases match the switch expression. The default label is optional, and there can only be one default label per switch statement. It is also typically declared as the last label in the switch block, though this is not strictly necessary.

In the isDigit() example above, if c is not an ASCII digit, the default case executes and returns false.

Switch execution and fall-through

One of the trickiest things about case statements is the way in which execution proceeds when a case is matched. When a case is matched (or the default is executed), execution begins at the first statement following that label and continues until one of the following termination conditions is true:
1) The end of the switch block is reached
2) A return statement occurs
3) A goto statement occurs
4) A break statement occurs

Note that if none of these termination conditions are met, cases will overflow into subsequent cases! Consider the following snippet:

This snippet prints the result:

2
3
4
5

This is probably not what we wanted! When execution flows from one case into another case, this is called fall-through. Fall-through is almost never desired by the programmer, so in the rare case where it is, it is common practice to leave a comment stating that the fall-through is intentional.

Break statements

A break statement (declared using the break keyword) tells the compiler that we are done with this switch (or while, do while, or for loop). After a break statement is encountered, execution continues with the statement after the end of the switch block.

Let’s look at our last example with break statements properly inserted:

Now, when case 2 matches, the integer 2 will be output, and the break statement will cause the switch to terminate. The other cases are skipped.

Warning: Forgetting the break statement at the end of the case statements is one of the most common C++ mistakes made!

Multiple statements inside a switch block

One other bit of weirdness about switches is that you can have multiple statements underneath each case without defining a new block.

Variable declaration and initialization inside case statements

You can declare, but not initialize, variables inside the case statements:

Note that although variable y was defined in case 1, it was used in case 2 as well. All cases are considered part of the same scope, so a declaration in one case can be used in subsequent cases.

This may seem a bit counter-intuitive, so let’s examine why. When you define a local variable like “int y;”, the variable isn’t created at that point -- it’s actually created at the start of the block it’s declared in. However, it is not visible (in scope) until the point of declaration. The declaration statement doesn’t need to execute -- it just tells the compiler that the variable can be used past that point. So with that in mind, it’s a little less weird that a variable declared in one case statement can be used in another cases statement, even if the case statement that declares the variable is never executed.

However, initialization of variables directly underneath a case label is disallowed and will cause a compile error. This is because initializing a variable does require execution, and the case statement containing the initialization may not be executed!

If a case needs to define and/or initialize a new variable, best practice is to do so inside a block underneath the case statement:

Rule: If defining variables used in a case statement, do so in a block inside the case (or before the switch if appropriate)

Quiz

1) Write a function called calculate() that takes two integers and a char representing one of the following mathematical operations: +, -, *, /, or % (modulus). Use a switch statement to perform the appropriate mathematical operation on the integers, and return the result. If an invalid operator is passed into the function, the function should print an error. For the division operator, do an integer division.

2) Define an enum (or enum class, if using a C++11 capable compiler) named Animal that contains the following animals: pig, chicken, goat, cat, dog, ostrich. Write a function named getAnimalName() that takes an Animal parameter and uses a switch statement to return the name for that animal as a std::string. Write another function named printNumberOfLegs() that uses a switch statement to print the number of legs each animal walks on. Make sure both functions have a default case that prints an error message. Call printNumberOfLegs() from main() with a cat and a chicken. Your output should look like this:

A cat has 4 legs.
A chicken has 2 legs.

Quiz answers

1) Show Solution

2) Show Solution

5.4 -- Goto statements
Index
5.2 -- If statements

193 comments to 5.3 — Switch statements

  • Shane

  • Michael

    Hi Alex,

    why enclosing the initialization with block will guarantee its execution?

    isn’t it so that the statements inside this block will only be executed when the case matches?

    Thank you!

    • Alex

      > why enclosing the initialization with block will guarantee its execution?

      It doesn’t -- the block will only be executed if case 1 is executed. The block allows us to define the variable.

      > isn’t it so that the statements inside this block will only be executed when the case matches?

      No, all statements after a case will execute regardless of whether there is a block.

  • KP

    Not sure why this code is giving me the location of the memory location of the animal and no. of legs rather than their name.

    Not sure why I can’t have a separate function to print the name?

    Here is my code -

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

    enum class Animals
    {
        Pig,
        Chicken,
        Goat,
        Cat,
        Dog,
        Ostrich
    };

    std::string getAnimalName(Animals animals)
    {
        switch (animals)
        {
        case Animals::Pig:
            return "Pig";
            break;
        case Animals::Chicken:
            return "Chicken";
            break;
        case Animals::Goat:
            return "Goat";
            break;
        case Animals::Cat:
            return "Cat";
            break;
        case Animals::Dog:
            return "Dog";
            break;
        case Animals::Ostrich:
            return "Ostrich";
            break;
        default:
            return "Error";
            break;
        }
    }

    void noOfLegs(Animals Animals)
    {
         switch (Animals)
        {
        case Animals::Chicken:
        case Animals::Ostrich:
            std:: cout << "2";
            break;

        case Animals::Goat:
        case Animals::Cat:
        case Animals::Dog:
        case Animals::Pig:
            std::cout << "4";
            break;

        default:
            std::cout<< "Error";
            break;
        }
    }

    void printName(Animals animals)
    {
        std::cout << "A " << getAnimalName << " has " << noOfLegs << " legs.\n";
    }

    int main()
    {
        printName(Animals::Cat);
        printName(Animals::Chicken);

        return 0;
    }

    • Alex

      Because function printName() is printing getAnimalName (the address of function getAnimalName) rather than getAnimalName() (the return value of the function call to function getAnimalName).

      • KP

        I tried -
        std::cout << "A " << getAnimalName(animals) << " has " << noOfLegs(animals) << " legs.\n";

        However, it says that the function doesn’t take 0 arguments.

        What should the printName() function actually say?

  • Kushagra

    Why this does not work?
    #include <iostream>
    #include "string"
    using namespace std;
    enum Animal
    {
        pig,
        chicken,
        goat,
        cat,
        dog,
        ostrich
    };
    Animal change (std::string x)
    {
        if(x=="cat")
            return Animal::cat;
        if(x=="dog")
            return Animal::dog;
      if(x=="ostrich")
            return Animal::ostrich;
      if(x=="pig")
            return Animal::pig;
      if(x=="chicken")
            return Animal::chicken;
      if(x=="goat")
            return Animal::goat;
            else
                std::cout <<"ERROR" << std::endl;

    }
    void printNumberOfLegs( Animal change(x))
    {
        switch (change(x))
        {
      case cat :
        case dog :
        case pig:
        case goat:
        std::cout << change(x) <<" has 4 LEGS. "    << std::endl;
      break;
      case chicken:
      case ostrich :
        std::cout << "has 2 LEGS. "  <<std::endl;
        break;
      default:
        std::cout <<" ERROR " <<std::endl;

        }

    }

    int main()
    {
    std::string x;
    std::getline(std::cin , x);
    Animal y = change(x);
    printNumberOfLegs(y);

        return 0;
    }

  • Zero Cool

    This is my solution for Quiz 2:

    animal.h

    animal.cpp

    main.cpp

  • Zero Cool

    This is my solution for Quiz 1:

    io.h

    io.cpp

    calculate.h

    calculate.cpp

    main.cpp

  • gary

    Hi, Alex. Below is my quiz 1, please give me some advice if any and one question while I was coding is, why a int calculate() is able to print out std::cout statement even it should be return an integer? I thought void is the only way to return a std::cout statement. Also, I remember i ran into (segment fault error) when i didn’t return int and only print message for a int function. Thanks for the patient and the help!!

    • Alex

      > why a int calculate() is able to print out std::cout statement even it should be return an integer?

      Because they’re two totally different things! std::cout prints to the console. std::cout has nothing to do with whether the function returns a value, or what specific value is returned.

      > I thought void is the only way to return a std::cout statement.

      This statement doesn’t make any sense to me.

      > Also, I remember i ran into (segment fault error) when i didn’t return int and only print message for a int function.

      Yes, some compilers will let you declare a function that returns a value, but then not actually return a value. If you do this, undefined behavior will result (which can cause crashes).

      • gary

        thanks alex!! I think i understand now, i was wrong of "void is the only way to return a std::cout statement", so it should be void has no return value but to print out the message right? thanks so much again!! will keep learning everyday from your site!! really helpful!! thanks

        • Alex

          A function with a void return type does not return any value to the caller. Full stop. Beyond that, the function can do whatever it wants, including printing messages.

  • Ryan

    Hey Alex,

    Are breaks not needed in cases that return a value?

    • Alex

      They are not. Breaks are used to exit the switch, but not the function. Return is used to exit the entire function (whether it returns a value or not), which also exits the switch. So if you use a return, break isn’t needed (if the break come before the return, the return wouldn’t execute; if the return came before the break, the break wouldn’t execute).

  • Ganesh

    Hey, Alex. Can you please tell me why this isn’t working?

    #include<iostream>
    #include<string>
    using str=std::string;
    enum animal
    {   pig,
        chicken,
        goat,
        cat,
        dog,
        ostrich
    };
    str getAnimalname(animal a)
    {   switch(a)
    {
        case pig:
        return "pig";
        case chicken:
        return "chicken";
        case goat:
        return "goat";
        case cat:
        return "cat";
        case dog:
        return "dog";
        case ostrich:
        return "ostrich";
    }
    }
    int nooflegs(animal a)
    {
        switch(a)
        {   case pig:
            case goat:
            case cat:
            case dog:
            return 4;
            break;
            case chicken:
            case ostrich:
            return 2;
        
    }}
    int main()
    {
        str a;
        std::cout<<"Enter animal name:";
        std::cin>>a;
        animal b = static_cast<animal>(a);
        std::cout<<getAnimalname(b)<<"has "<<nooflegs(b)<<" legs";
        return 0;
    }

    • Alex

      You’re trying to static_cast a std::string (a) to an animal (b). You can’t do that.

      If you want to convert a string to an animal, you’ll have to write a function and do all of the string comparisons yourself, returning the proper animal when you find a match.

  • Evan

    Hey Alex. Any idea why this does not work without the Animal enumeration before the members?

    // ConsoleApplication2.cpp : Defines the entry point for the console application.
    //

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

    enum class Animal
    {
        PIG,
        CHICKEN,
        GOAT,
        CAT,
        DOG,
        OSTRICH
    };

    std::string getAnimalName(Animal animal)
    {
        switch (animal)
        {
        case Animal::PIG:
            return "Pig";
        case Animal::CHICKEN:
            return "Chiken";
        case Animal::GOAT:
            return "Goat";
        case Animal::CAT:
            return "Cat";
        case Animal::DOG:
            return "Dog";
        case Animal::OSTRICH:
            return "Ostrich";
        default:
            return "Not a valid animal.";
        }
    }

    void printNumberOfLegs(Animal animal)
    {
        std::cout << "A " << getAnimalName(animal) << " has ";

        switch (animal)
        {
        case Animal::CHICKEN:
        case Animal::OSTRICH:
            std::cout << "2";
            break;
        case Animal::PIG:
        case Animal::CAT:
        case Animal::DOG:
        case Animal::GOAT:
            std::cout << "4";
        default:
            std::cout << "getAnimalName(): unhandled enumeration.";
            break;
        }

        std::cout << " legs. \n";
    }

    int main()
    {
        printNumberOfLegs(Animal::CHICKEN);
        printNumberOfLegs(Animal::DOG);

        return 0;
    }

    • Alex

      Because you’ve declared Animal as an enum class (not a regular enum). In enum classes, the enumerators are in the namespace of the enumeration, and thus need to be prefixed.

  • D Brown

    I noticed while looking at your solution that I can’t get mine to work with the way you’ve used the the Animal type. For example you access the Animal Type purely by into entering the type (Animal_Pig) mean while I have to "index" into it (Animal::Pig). Can you explain what is happening here and what the difference is?

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

    enum class Animal
    {
        PIG,
        CHICKEN,
        GOAT,
        CAT,
        DOG,
        OSTRICH
    };

    std::string getAnimalName(Animal animal)
    {
        switch (animal)
        {
            case Animal::PIG:
                return "PIG";
            case Animal::CHICKEN:
                return "CHICKEN";
            case Animal::GOAT:
                return "GOAT";
            case Animal::CAT:
                return "CAT";
            case Animal::DOG:
                return "DOG";
            case Animal::OSTRICH:
                return "OSTRICH";
            default:
                return "Error: Incorrect animal type.";
        }
    }

    void printNumberOfLegs(Animal animal)
    {
        using namespace std;

        switch (animal)
        {
            case Animal::PIG:
                cout << "A " << getAnimalName(animal) << " has 4 legs.\n";
                break;
            case Animal::CHICKEN:
                cout << "A " << getAnimalName(animal) << " has 2 legs.\n";
                break;
            case Animal::GOAT:
                cout << "A " << getAnimalName(animal) << " has 4 legs.\n";
                break;
            case Animal::CAT:
                cout << "A " << getAnimalName(animal) << " has 4 legs.\n";
                break;
            case Animal::DOG:
                cout << "A " << getAnimalName(animal) << " has 4 legs.\n";
                break;
            case Animal::OSTRICH:
                cout << "A " << getAnimalName(animal) << " has 2 legs.\n";
                break;
            default:
                cout << "Error: Incorrect animal type.\n";
                break;
        }
    }

    int main()
    {

        printNumberOfLegs(

    );
        printNumberOfLegs(

    );

    }

  • Hello!! is this good for the first quiz??

    • Alex

      Mostly. A few minor nitpicks:
      * You should declare x, y, and symbol as close to their first use as possible.
      * Your Calculate function doesn’t need to return anything
      * You’re trying to return 3 values, which doesn’t work.
      * There’s no point in having main() just call Calculate() and do nothing else. You can put all your code in main().

  • c++ learner

    is this correct? I mean is this a good way to right this problem or not

  • James Ray

    Here’s my code for question 2 (with a slight variation to the solution, using "a" if the animal starts with a consonant, and "an" if the animal starts with a vowel. Note that knowing how to extract parts of a string would be useful for this, along with an if statement. Hopefully, Alex will teach us that later ;)):
    [code]
    // AnimalLegs.cpp : Defines the entry point for the console application.
    //

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

    /*Define an enum (or enum class, if using a C++11 capable compiler) named Animal that contains the following animals:
    pig, chicken, goat, cat, dog, ostrich.*/

    enum class Animal
    {
        PIG,
        CHICKEN,
        GOAT,
        CAT,
        DOG,
        OSTRICH
    };
    /*
    Write a function named getAnimalName() that takes an Animal parameter and uses
    a switch statement to return the name for that animal as a std::string.
    */

    std::string getAnimalName (Animal animal)
    {
        switch (animal)
        {
            case Animal::CHICKEN:
                return "A chicken";
                break;
            case Animal::OSTRICH:
                return "An ostrich";
                break;
            case Animal::PIG:
                return "A pig";
                break;
            case Animal::GOAT:
                return "A goat";
                break;
            case Animal::CAT:
                return "A cat";
                break;
            case Animal::DOG:
                return "A dog";
                break;
            default:
                return "getAnimalName(): unhandled enumerator class.\n";
                break;
        }
    }
    /*
    Write another function named printNumberOfLegs() that uses a switch statement to print the number of legs each animal walks on.
    Make sure both functions have a default case that prints an error message.
    Call printNumberOfLegs() from main() with a cat and a chicken.
    Your output should look like this:

    A cat has 4 legs.
    A chicken has 2 legs.
    */
    void printNumberOfLegs(Animal animal)
    {
        using namespace std;
        cout << getAnimalName(animal) << " has ";

        switch (animal)
        {
            case Animal::CHICKEN:
            case Animal::OSTRICH:
                cout << "2";
                break;

            case Animal::PIG:
            case Animal::GOAT:
            case Animal::CAT:
            case Animal::DOG:
                cout << "4";
                break;

            default:
                cout << "printNumberOfLegs(): unhandled enumerator class.\n";
                break;
        }

        cout << " legs.\n";
    }
    int main()
    {
        printNumberOfLegs(Animal::CAT);
        printNumberOfLegs(Animal::CHICKEN);
        printNumberOfLegs(Animal::OSTRICH);
        
        return 0;
    }
    [code]

  • James Ray

    I just discovered something very useful about Microsoft Visual Studio Community 2015. It tries to automatically pre-fill functions.

    For instance when writing code for question 2:

    As soon as I type "{" it automatically puts in the closing brace. When I press enter it indents the line

    When typing switch, the function comes up in the dropdown menu, and if I press tab once then it will fill in the function with:

    If I change the parameter to Animal, and press tab, then I get:
    [code]
    getAnimalName(Animal animal)
    {
        switch (animal)
        {
        case Animal::PIG:
            break;
        case Animal::CHICKEN:
            break;
        case Animal::GOAT:
            break;
        case Animal::CAT:
            break;
        case Animal::DOG:
            break;
        case Animal::OSTRICH:
            break;
        default:
            break;
        }
    }

    All I have to do then for switch statement is enter statements to save the name for each animal as a std::string for each case!

  • James Ray

    Hi Alex,

    You’ve used a comma before and in a few instances where it is not correct to do so:[1]
    <li>"The first kind of label is the case label, which is declared using the case keyword, and followed by a constant expression."</li>
    <li>"However, initialization of variables directly underneath a case label is disallowed, and will cause a compile error."</li>
    <li>""</li>
    <li>""</li>

    Rather than using two dashes (like this: "-"), you can use an em dash by typing ALT+0151 using the numpad for the numbers (hold alt down while typing 0, 1, 5 and 1 in succession). Similarly, for an en dash you can use ALT+0150.

    I had some minor variations on my code for this first question. I used breaks for each case and used the namespace std in the main function.

    References:
    [1] <a href="http://www.getitwriteonline.com/archive/020204whencommabfand.htm">"When to Use a Comma before "And""</a>, Get It Write, Published Mar 5, 2017, accessed 5 March 2017, <http://www.getitwriteonline.com/archive/020204whencommabfand.htm>

  • Nguyen Long

    Dear Mr.Alex,
    Thank you for your lesson,
    I have a problem with my program; here is mine

    // Example program

    #include <iostream>
    #include <string>
    enum Teama //include an enum
    {
        Low,
        Neuer,
        Schweinsteiger,
        Lahm,
        Muller,
        Klose,
        Boateng,
        Reus,
        Poldoski,
        Ozil,
    };

    std::string printplayers (Teama, int b) // return the name by the number
    {
        switch (b)
        {
            case 1:
            return "Neuer";
            case 2:
            return "Schweinsteiger";
            case 3:
            return "Lahm";
            case 4:
            return "Muller";
            case 5:
            return "Klose";
            case 6:
            return "Boateng";
            case 7:
            return "Reus";
            case 8:
            return "Poldoski";
            case 9:
            return "Ozil";
            default:
            return "failed";
        }
    }
            
    int main()
    {
        int a;
        std::cout << "Enter number";
        std::cin >> a; //input a
        std::cout << printplayers (Teama, a); //error here
        return 0;
    }

    I have an error that read "expected-primary expression before "," token".
    I don’t know what is it talking about
    When I delete Teama and only leave a,  it read too few argument and can’t invalid conversation between "a"and Teama
    Can you suggest me what wrong is it?
    Thank you very much

    • Alex

      doesn’t make any sense. You only need a Teama parameter (you can name it b if you want). Inside the switch statement, you should switch on the enumerators, not integer values.

      When you call printplayers(), you’ll need to static_cast a from an int to a Teama to pass it into the function as an argument.

  • Matheus

    Hi, I’ve been using code without the #include<string> and it is working. I’m using C++14.

    Is #include<string> not necessary anymore?

    (For example, take quiz 2 answer and comment the #include <string>).

    • Alex

      It’s still needed. Some compilers may opt to include it for you, or you may be including other headers that themselves include string, so you’re getting it as a side effect of including those. But best practice is to always include all of the headers you need. Otherwise your code won’t be compilable on other compilers / platforms.

  • The Long

    Hi, I’m a beginner to C++ and your lessons have helped me a great deal so far. AS far as I know, BREAK will terminate the current block and continue to execute the statements outside of it. Why in this case BREAK does not terminate the nested block and make the SWITCH fallthrough  the default case? Please explain, thank you very much.

    • Alex

      Break does not just terminate the current block. When used inside a switch statement, break terminates the entire switch statement. When used inside a loop, break terminates the nearest enclosing loop. This means more than one nested block might be exited to get to that point.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter