Switch Statement
COP-3223H
Table of Contents
switch statements
switch (expression) { case value0: instructions0; break; case value1: instructions1; break; case value2: instructions2; break; ... // any number of cases default: default_instructions; break; }
- Evaluate the expression
- Jump to the case corresponding to its value.
- The break statement jumps to the end of the switch
The "break" statement is necessary to avoid "fall-through"
The values can be in any order.
Not all values need to be there.
The default is optional; without it, it's possible that none of the cases will run (like an if without an else).
Example: even or odd
switch (x % 2) { case 0: printf("even\n"); break; case 1: printf("odd\n"); break; default: printf("this should never happen\n"); assert(0); break; }
Like else-if statements
if (0 == (x % 2)) { printf("even\n"); } else if (1 == (x % 2)) { printf("odd\n"); } else { printf("this should never happen\n"); assert(0); }
Simpler syntax for a specific case of conditionals
Example: reading user input
switch (c) { case 'j': printf("pressed j, which is down\n"); break; case 'k': printf("pressed k, which is up\n"); break; case 'h': printf("pressed h, which is left\n"); break; case 'l': printf("pressed l, which is right\n"); break; default: printf("unexpected key\n"); break; }
if ('j' == c) { printf("pressed j, which is down\n"); } else if ('k' == c) { printf("pressed k, which is up\n"); } else if ('h' == c) { printf("pressed h, which is left\n"); } else if ('l' == c) { printf("pressed l, which is right\n"); } else { printf("unexpected key\n"); }
Example: moving a character
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <termios.h> /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } int main(int argc, char **argv) { char c = '\0'; int width = 40; int height = 20; int x = 1; int y = 1; int dx = 1; int dy = 1; set_input_mode (); while (1) { printf("\x1b[2J"); printf("\x1b[H"); printf("\033[%d;%dH", y, x); putchar('o'); putchar('\n'); printf("\033[%d;%dH", height + 1, 0); printf("y: %d\n", y); printf("x: %d\n", x); printf("c: %c\n", c); read (STDIN_FILENO, &c, 1); dx = 0; dy = 0; switch (c) { case 'j': dy = 1; break; case 'k': dy = -1; break; case 'h': dx = -1; break; case 'l': dx = 1; break; case 's': dy = 1; break; case 'w': dy = -1; break; case 'a': dx = -1; break; case 'd': dx = 1; break; } int newx = x + dx; int newy = y + dy; if ((0 < newx) && (newx < width)) { x = newx; } if ((0 < newy) && (newy < height)) { y = newy; } } }
C gotcha: fall-through
switch (x % 2) { case 0: printf("even\n"); break; case 1: printf("odd\n"); default: printf("this should never happen\n"); }
Without a "break", the program will continue running the next case.
case labels are just like labels for goto. The "break" here means goto to end of the switch block.
Intentional fall-through
When you want multiple cases to have the same behavior.
E.g., checking for an ASCII digit (as an alternatively to range checks).
Famous example: Duff's device - Wikipedia