Switch and For Statements, Command Line and File Handling - The switch statement

Chapter chap9 section 3

The switch statement provides a very useful alternative to multiple if statements. It is used in conjunction with the case and default statements. The syntax is

switch(integral expression) statement

the controlled statement, known as the switch body will consist of a sequence of case statements. The syntax of a case statement is

case constant-integral-expression : statement

this is really nothing more than a labelled statement. The meaning of all this is that flow of control passes to the statement whose case label matches the value of the switch expression. The flow of control then continues from that point until a break is encountered or the end of the switch body is encountered. A break statement takes control out of the switch body.

If none of the case labels match the value of the switch expression then no part of the code in the switch body is executed unless a default statement appears within the switch body, this acts as a "catch-all" label when no other case label matches.

An example is in order. This is a variant of a program that has already been seen. It reads in simple expressions and evaluates them.

#include	<stdio.h>
main()
{
	int	n1,n2;
	char	c;
	char	inbuf[30];
	while(1)
	{
		printf("Enter Expression ");
		if(gets(inbuf) == NULL) break;
		sscanf(inbuf,"%d%c%d",&n1,&c,&n2);
		switch(c)
		{
			case '+' :
				printf("%d\n",n1+n2);
				break;
			case '-' :
				printf("%d\n",n1-n2);
				break;
			case '*' :
				printf("%d\n",n1*n2);
				break;
			case '/' :
				printf("%d\n",n1/n2);
				break;
			default :
				printf("Unknown operator %c\n",c);
		}
	}
}
A typical dialogue is shown below
Enter Expression 345+45
390
Enter Expression 212/6
35
Enter Expression 234-5
229
Enter Expression 234%4
Unknown operator %

Notice the frequent break statements in the switch body, these are necessary to avoid the drop-through between cases. Many people think this drop-through is annoying and the language would be better if a break from the switch body was implicit at the end of each case , however it can sometimes be useful as this example shows.
#include	<stdio.h>
main()
{
	int	c;
	int	dcnt = 0;	/* digits */
	int	wcnt = 0;	/* white space count */
	int	ocnt = 0;	/* others count */
	while((c=getchar())!=EOF)
		switch(c)
		{
			case '0' :
			case '1' :
			case '2' :
			case '3' :
			case '4' :
			case '5' :
			case '6' :
			case '7' :
			case '8' :
			case '9' :
				dcnt++;
				break;
			case ' ' :
			case '\t' :
			case '\n' :
				wcnt++;
				break;
			default :
				ocnt++;
		}
	printf("%d digits\n%d white spaces"
		"\n%d others\n",dcnt,wcnt,ocnt);
}
When it consumed its own source the program produced the following output
13 digits
164 white spaces
336 others
A more elaborate use of switch statements is illustrated by the following program that extracts comments from C programs. It is not fooled by comment-like things within string constants but escaped double quotes within strings would cause the program to fail.
/*	A program to extract comments */
#include	<stdio.h>
#define	LEAD	0	/* In normal text */
#define	PSCOM	1	/* Possible start of comment */
#define	INCOM	2	/* Processing Comment */
#define	PECOM	3	/* Possible end of comment */
#define	INSTR	4	/* In string constant */
main()
{
	int	c;	/* input character */
	int	state = LEAD;	/* current status */
	char	*dummy = "/* comment in string */";
	while((c=getchar())!=EOF)
	{
		switch(state)
		{
		case LEAD :
			switch(c)
			{
				case '/' :
					state = PSCOM;
					break;
				case '"' :
					state = INSTR;
					break;
			}
			break;
		case PSCOM :
			switch(c)
			{
				case '*' :
					state = INCOM;
					break;
				case '"' :
					state = INSTR;
					break;
				default :
					state = LEAD;
					break;
			}
			break;
		case INCOM :
			switch(c)
			{
				case '*' :
					state = PECOM;
					break;
				default :
					putchar(c);
					break;
			}
			break;
		case PECOM :
			switch(c)
			{
				case '/' :
					state = LEAD;
					putchar('\n');
					break;
				default :
					state = INCOM;
					putchar('*');
					putchar(c);
					break;
			}
			break;
		case INSTR :
			switch(c)
			{
				case '"' :
					state = LEAD;
					break;
				default :
					break;
			}
			break;
		}
	}
}
When presented with its own source as input the program produced the following output.
	A program to extract comments 
 In normal text 
 Possible start of comment 
 Processing Comment 
 Possible end of comment 
 In string constant 
 input character 
 current status 
This use of nested switches, whilst it makes for rather clumsy coding, stems from a very simple design technique known as a state switch. The whole operation of the program is described by the following transition table.
       +-------+-------+-----------+-----------+-------+
       | LEAD  | PSCOM | INCOM     | PECOM     | INSTR |
+------+-------+-------+-----------+-----------+-------+
|   /  | PSCOM | LEAD  | INCOM     | LEAD      | INSTR |
|      |       |       | print /   | print \n  |       |
+------+-------+-------+-----------+-----------+-------+
|   *  | LEAD  | INCOM | PECOM     | INCOM     | INSTR |
|      |       |       |           | print * * |       |
+------+-------+-------+-----------+-----------+-------+
|   "  | INSTR | INSTR | INCOM     | INCOM     | LEAD  |
|      |       |       | print "   | print * " |       |
+------+-------+-------+-----------+-----------+-------+
|other | LEAD  | LEAD  | INCOM     | INCOM     | INSTR |
|      |       |       | print ch  | print * ch|       |
+------+-------+-------+-----------+-----------+-------+

The table entries represent the new value of "state" and the action to be taken depending on the current input character (shown in the left hand column) and the current value of state (shown in the top row). In some circumstances as well as changing the value of state it is necessary to take some sort of action, in this case printing out a particular character or the current input character ("ch").


Command Line Arguments