A instrução switch é uma estrutura de controle de fluxo em C que permite selecionar um entre vários blocos de código com base no valor de uma expressão inteira. Ela é uma alternativa mais legível e eficiente a uma cadeia de if-else if quando você precisa comparar uma variável com vários valores constantes. Nesta aula, vamos mergulhar na sintaxe, no comportamento do break, no fall-through, no uso do default e nas limitações dessa construção.

Ao dominar o switch, você será capaz de escrever código mais claro e organizado para menus, máquinas de estado e despacho de comandos. Além disso, entenderá as nuances que podem causar bugs sutis, como o fall-through acidental.

Sintaxe

A sintaxe básica do switch é a seguinte:

switch (expressão) {
    case constante1:
        // bloco de código para constante1
        break;
    case constante2:
        // bloco de código para constante2
        break;
    // ... mais casos
    default:
        // bloco executado se nenhum caso corresponder
}

A expressão avaliada deve ser de tipo inteiro (int, char, enum, etc.). Os valores nos rótulos case devem ser constantes de tempo de compilação, ou seja, valores conhecidos durante a compilação. Cada case pode conter uma ou mais instruções, e o bloco termina quando um break é encontrado ou quando o final da instrução switch é atingido (o que causaria fall-through).

Vejamos um exemplo simples:

#include <stdio.h>

int main() {
    int dia = 3;
    switch (dia) {
        case 1:
            printf("Domingo\n");
            break;
        case 2:
            printf("Segunda-feira\n");
            break;
        case 3:
            printf("Terça-feira\n");
            break;
        default:
            printf("Dia inválido\n");
    }
    return 0;
}

Nesse exemplo, a variável dia é comparada com os valores 1, 2 e 3. Como dia é 3, o programa imprime "Terça-feira".

break e fall-through

O break é uma instrução que interrompe a execução do switch e pula para a próxima instrução após o bloco. Sem o break, ocorre o chamado fall-through: a execução continua nos casos seguintes, mesmo que não correspondam ao valor avaliado. Isso pode ser útil em algumas situações, mas muitas vezes é um erro.

Exemplo de fall-through intencional:

int dia = 3;
switch (dia) {
    case 1:
    case 2:
    case 3:
        printf("É um dia útil (segunda a terça)\n");
        break;
    case 4:
        printf("Quarta-feira\n");
        break;
    default:
        printf("Fim de semana ou inválido\n");
}

Aqui, os casos 1, 2 e 3 compartilham o mesmo código, porque não há break entre eles. Isso é uma técnica comum para agrupar valores.

Porém, o fall-through acidental é uma fonte comum de bugs. Considere:

int x = 2;
switch (x) {
    case 1:
        printf("Um\n");
    case 2:
        printf("Dois\n");
    case 3:
        printf("Três\n");
}

Se x for 2, a saída será "Dois" e "Três" porque não há break após o caso 2. Para evitar isso, sempre coloque break a menos que você queira o fall-through.

default

A cláusula default é executada quando nenhum dos case corresponde ao valor da expressão. Ela é opcional, mas recomendada para tratar valores inesperados. Pode aparecer em qualquer lugar dentro do switch, mas geralmente é colocada no final.

Exemplo com default:

char opcao = 'B';
switch (opcao) {
    case 'A':
        printf("Adicionar\n");
        break;
    case 'B':
        printf("Buscar\n");
        break;
    case 'C':
        printf("Cancelar\n");
        break;
    default:
        printf("Opção inválida\n");
}

Se opcao for 'B', imprime "Buscar". Se for 'X', imprime "Opção inválida". O default também pode ser usado para capturar erros e fornecer feedback ao usuário.

É importante notar que o default não precisa ser o último, mas se não houver break no default e ele não for o último, pode causar fall-through também.

Limitações

O switch em C tem várias limitações em comparação com outras linguagens:

  • Apenas tipos inteiros: A expressão deve ser de tipo inteiro (int, char, enum). Não é possível comparar strings, floats ou ponteiros diretamente.
  • Constantes de tempo de compilação: Os valores nos rótulos case devem ser constantes literais ou expressões constantes (por exemplo, macros). Não podem ser variáveis ou expressões que dependam de valores em tempo de execução.
  • Sem intervalos: Diferente de algumas linguagens, C não suporta intervalos como case 1 ... 10. Você precisa listar cada valor ou usar fall-through.
  • Não há verificação de escopo implícita: Se você declarar variáveis dentro de um case, elas podem causar problemas de escopo. É recomendável usar chaves {} para criar um bloco, mas as variáveis ainda são visíveis em todo o switch se não forem inicializadas corretamente.
  • Dificuldade com lógica complexa: Para condições mais complexas (como intervalos ou comparações), if-else é mais adequado.

Apesar dessas limitações, o switch é muito útil para despachar comandos e menus, onde a clareza e a eficiência são importantes.

Boas práticas

  • Sempre use break ao final de cada case, a menos que haja fall-through intencional.
  • Inclua default para tratar valores inesperados.
  • Use chaves {} para isolar variáveis locais em cada case, evitando conflitos de declaração.
  • Evite switch sobre expressões com muitos casos (mais de 20) – considere uma tabela de ponteiros para função.
  • Mantenha os casos em ordem numérica ou alfabética para melhor legibilidade.

Exercícios

  1. Escreva um programa que leia um número de 1 a 7 e imprima o dia da semana correspondente, usando switch. Inclua default para números fora do intervalo.
  2. ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int num;
        printf("Digite um número de 1 a 7: ");
        scanf("%d", &num);
        switch (num) {
            case 1: printf("Domingo\n"); break;
            case 2: printf("Segunda-feira\n"); break;
            case 3: printf("Terça-feira\n"); break;
            case 4: printf("Quarta-feira\n"); break;
            case 5: printf("Quinta-feira\n"); break;
            case 6: printf("Sexta-feira\n"); break;
            case 7: printf("Sábado\n"); break;
            default: printf("Número inválido\n");
        }
        return 0;
    }
  3. Explique o que acontece se você omitir o break em um case. Dê um exemplo de código que demonstre o fall-through e a saída gerada.
  4. ✓ Resposta: Se o break for omitido, a execução continua no próximo case, mesmo que o valor não corresponda. Isso é chamado de fall-through. Exemplo:
    int x = 2;
    switch (x) {
        case 1:
            printf("Um\n");
        case 2:
            printf("Dois\n");
        case 3:
            printf("Três\n");
    }
    A saída será "Dois" e "Três" porque não há break após o caso 2.
  5. Usando o fall-through intencional, escreva um programa que classifique uma nota (0-10) como "Reprovado" para notas < 5, "Recuperação" para 5-6, e "Aprovado" para 7-10. Use switch com agrupamento de casos.
  6. ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int nota;
        printf("Digite a nota (0-10): ");
        scanf("%d", &nota);
        switch (nota) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
                printf("Reprovado\n");
                break;
            case 5:
            case 6:
                printf("Recuperação\n");
                break;
            case 7:
            case 8:
            case 9:
            case 10:
                printf("Aprovado\n");
                break;
            default:
                printf("Nota inválida\n");
        }
        return 0;
    }
  7. Escreva um programa que use switch para operações aritméticas simples: leia dois números e um operador (+, -, *, /) e imprima o resultado. Use default para operador inválido.
  8. ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        double a, b, resultado;
        char op;
        printf("Digite dois números: ");
        scanf("%lf %lf", &a, &b);
        printf("Digite o operador (+, -, *, /): ");
        scanf(" %c", &op);
        switch (op) {
            case '+': resultado = a + b; break;
            case '-': resultado = a - b; break;
            case '*': resultado = a * b; break;
            case '/':
                if (b == 0) {
                    printf("Erro: divisão por zero\n");
                    return 1;
                }
                resultado = a / b; break;
            default:
                printf("Operador inválido\n");
                return 1;
        }
        printf("Resultado: %.2f\n", resultado);
        return 0;
    }
  9. Explique as limitações do switch em C. Cite pelo menos três e dê um exemplo de situação em que if-else seria mais adequado.
  10. ✓ Resposta: As limitações incluem: suporte apenas a tipos inteiros, valores de caso devem ser constantes de tempo de compilação, e não permite intervalos. Por exemplo, para verificar se uma variável x está em um intervalo (ex.: 10 < x < 20), if-else é mais adequado:
    if (x > 10 && x < 20) {
        printf("Entre 10 e 20\n");
    } else {
        printf("Fora do intervalo\n");
    }

Referências