| | |
Lookup tables - how to perform a switch using a string
Please support our C++ advertiser: Programming Forums - DaniWeb Sister Site
![]() |
Intro
The focus of this tutorial is the code relating to decision making and selection, and not the I/O code. I do not advocate using scanf() in this way for anything other than testing blocks of code in 'toy' programs. If you feel the need to use scanf() when writing more serious programs, please read this: http://c-faq.com/stdio/scanfprobs.html
Switch statement selection
A common question from C beginners comes along the lines of "How can I use a switch statement with a string or a character array?" (It was a question similar to this which prompted the creation of this tutorial) to which the short and simple answer is: You can't. Because a switch statement requires an integral value, such as int, long or char. A similar cry is often heard from beginners to C++ and Java. The usual solution is to write an if/else block instead - but this loses some of the simplicity and brevity which can make switch statements more attractive.
A more in-depth answer to this question may be that there is a workaround available, which allows the use of a switch statement, with the ability to make a decision based on a string.
The 'vending machine' program
Given a common beginner problem to introduce switch statements, the 'vending machine', where a user types in their choice of drink/snack/etc, the program is generally restricted to a numbered menu
Typical Output Such a program may be written as follows (For brevity, this tutorial only deals with the selection code)
Aside from only handling integer input, the use of integer values loses the meaning of the code. At least that can be easily improved using enumerated constants - But this still doesn't address the issue that selection must be based on an integer, rather than a human readable word or sentence.
Allowing string input - The wrong way!
One possible solution may be a helper function which takes a string as input, and returns a value based on a set of if/else statements. Rather than passing the user's input directly to the switch, we can use this function to resolve the input to an integral value that is acceptable to the switch statement. Another enumerated value, ITEM_NONE, has been added, so that the lookup function is able to return a value when the user's input does not match any of the available snack names.
Overall, this is a very poor solution, and merely adds an extra level of selection. In fact, it puts back into play the ugly if/else block which we were trying to avoid in the first place - The switch statement here suddenly becomes completely superfluous.
Allowing string input - A better way!
What we need is another way to resolve the string to an integer. The answer is to perform a kind of reverse lookup using an array, which holds a list of all the available snacks' names from the vending machine. Every position in an array has a unique index number, which will correspond directly with one of the lines in the switch statement. The important fact here is that enum statements and arrays both naturally begin at 0. The lookup() function is an example of a simple linear search algorithm, which returns the position of the snack name inside our lookup_table array.
The position found by this reverse lookup process is solely based on the user's input. If the user's input is not matched to any snack name in lookup_table, the function returns ITEM_NONE, as before.
Since the position of the snack name in lookup_table is designed to synchronise with the enum statement, it is imperative when altering the lookup table, that the enum statement is altered to match. The fact that the two are entirely dependent on each another is a serious drawback, so this method should be used with care (However, under a different design approach, it would be possible to create a lookup system without this dependency).
Improving the lookup table
One more problem with this code, is case-sensitivity. currently, if the user types "CHOCOLATE" or "Chocolate" instead of "chocolate", the program will output a message claiming the selection is invalid. The user's input must first be converted to lowercase, so that its recognised by the search algorithm
In summary
There's nothing stopping this method being adapted for Python, C++, Java, or any other language, However, other languages could make this program far simpler through the use of their own container libraries to handle Strings, Arrays and Search algorithms (for example C++ has std::string, std::vector and std::find ).
The real focus of this tutorial should show how versatile the concept of lookup tables can be when associating the program's behaviour with different data values, regardless of their type. Extending the capabilities of a switch statement is only one limited use for this technique. Selection can be fairly long and unweildy - in this example, it would be possible to remove the selection process entirely using lookups from data structures, however, that extends beyond the scope of this tutorial.
The focus of this tutorial is the code relating to decision making and selection, and not the I/O code. I do not advocate using scanf() in this way for anything other than testing blocks of code in 'toy' programs. If you feel the need to use scanf() when writing more serious programs, please read this: http://c-faq.com/stdio/scanfprobs.html
Switch statement selection
A common question from C beginners comes along the lines of "How can I use a switch statement with a string or a character array?" (It was a question similar to this which prompted the creation of this tutorial) to which the short and simple answer is: You can't. Because a switch statement requires an integral value, such as int, long or char. A similar cry is often heard from beginners to C++ and Java. The usual solution is to write an if/else block instead - but this loses some of the simplicity and brevity which can make switch statements more attractive.
A more in-depth answer to this question may be that there is a workaround available, which allows the use of a switch statement, with the ability to make a decision based on a string.
The 'vending machine' program
Given a common beginner problem to introduce switch statements, the 'vending machine', where a user types in their choice of drink/snack/etc, the program is generally restricted to a numbered menu
Typical Output
C++ Syntax (Toggle Plain Text)
"Press 1 for chocolate" "Press 2 for biscuits" "Press 3 for crisps" etc.
C Syntax (Toggle Plain Text)
#include <stdio.h> int main() { int input; printf("Enter the snack number: "); scanf("%d", &input); switch ( input ) { case 0: printf("Walkers Cheese & Onion\n"); break; case 1: printf("Cadburys Dairy Milk\n"); break; case 2: printf("Schweppes Lemonade\n"); break; case 3: printf("McVities Digestives\n"); break; default: printf("Invalid selection\n"); } return 0; }
C Syntax (Toggle Plain Text)
#include <stdio.h> enum { ITEM_CRISPS, ITEM_CHOCOLATE, ITEM_LEMONADE, ITEM_BISCUITS }; int main() { int input; printf("Enter the snack number: "); scanf("%d", &input); switch ( input ) { case ITEM_CRISPS: printf("Walkers Cheese & Onion\n"); break; case ITEM_CHOCOLATE: printf("Cadburys Dairy Milk\n"); break; case ITEM_LEMONADE: printf("Schweppes Lemonade\n"); break; case ITEM_BISCUITS: printf("McVities Digestives\n"); break; default: printf("Invalid selection\n"); } return 0; }
Allowing string input - The wrong way!
One possible solution may be a helper function which takes a string as input, and returns a value based on a set of if/else statements. Rather than passing the user's input directly to the switch, we can use this function to resolve the input to an integral value that is acceptable to the switch statement.
C Syntax (Toggle Plain Text)
#include <stdio.h> #include <string.h> enum { ITEM_CRISPS, ITEM_CHOCOLATE, ITEM_LEMONADE, ITEM_BISCUITS, ITEM_NONE }; int lookup(char* snack) { if( strcmp(snack, "crisps") == 0 ) return ITEM_CRISPS; else if( strcmp(snack, "chocolate") == 0 ) return ITEM_CHOCOLATE; else if( strcmp(snack, "lemonade") == 0 ) return ITEM_LEMONADE; else if( strcmp(snack, "biscuits") == 0 ) return ITEM_BISCUITS; else return ITEM_NONE; } int main() { char* input; printf("Enter the snack's name: "); scanf("%s", input); switch ( lookup(input) ) { case ITEM_CRISPS: printf("Walkers Cheese & Onion\n"); break; case ITEM_CHOCOLATE: printf("Cadburys Dairy Milk\n"); break; case ITEM_LEMONADE: printf("Schweppes Lemonade\n"); break; case ITEM_BISCUITS: printf("McVities Digestives\n"); break; default: printf("Invalid selection\n"); } return 0; }
Overall, this is a very poor solution, and merely adds an extra level of selection. In fact, it puts back into play the ugly if/else block which we were trying to avoid in the first place - The switch statement here suddenly becomes completely superfluous.
Allowing string input - A better way!
What we need is another way to resolve the string to an integer. The answer is to perform a kind of reverse lookup using an array, which holds a list of all the available snacks' names from the vending machine. Every position in an array has a unique index number, which will correspond directly with one of the lines in the switch statement.
C Syntax (Toggle Plain Text)
#include <stdio.h> #include <string.h> enum { ITEM_CRISPS, ITEM_CHOCOLATE, ITEM_LEMONADE, ITEM_BISCUITS, ITEM_NONE }; const char* lookup_table[] = { "crisps", "chocolate", "lemonade", "biscuits" }; int lookup(char snack[]) { const int available_snacks = sizeof lookup_table / sizeof *lookup_table; for(int i=0; i!= available_snacks; i++) if( strcmp( snack, lookup_table[i]) == 0 ) return i; return ITEM_NONE; } int main() { char* input; printf("Enter the snack's name: "); scanf("%s", input); switch ( lookup(input) ) { case ITEM_CRISPS: printf("Walkers Cheese & Onion\n"); break; case ITEM_CHOCOLATE: printf("Cadburys Dairy Milk\n"); break; case ITEM_LEMONADE: printf("Schweppes Lemonade\n"); break; case ITEM_BISCUITS: printf("McVities Digestives\n"); break; default: printf("Invalid selection\n"); } return 0; }
The position found by this reverse lookup process is solely based on the user's input. If the user's input is not matched to any snack name in lookup_table, the function returns ITEM_NONE, as before.
Since the position of the snack name in lookup_table is designed to synchronise with the enum statement, it is imperative when altering the lookup table, that the enum statement is altered to match. The fact that the two are entirely dependent on each another is a serious drawback, so this method should be used with care (However, under a different design approach, it would be possible to create a lookup system without this dependency).
Improving the lookup table
One more problem with this code, is case-sensitivity. currently, if the user types "CHOCOLATE" or "Chocolate" instead of "chocolate", the program will output a message claiming the selection is invalid. The user's input must first be converted to lowercase, so that its recognised by the search algorithm
C Syntax (Toggle Plain Text)
#include <stdio.h> #include <string.h> #include <ctype.h> const char* lookup_table[] = { "crisps", "chocolate", "lemonade", "biscuits" }; enum { ITEM_CRISPS, ITEM_CHOCOLATE, ITEM_LEMONADE, ITEM_BISCUITS, ITEM_NONE }; void convert_lowercase(char str[]) { for(int i=0; i!=strlen(str); i++) str[i] = tolower(str[i]); } int lookup(char snack[]) { convert_lowercase(snack); const int available_snacks = sizeof lookup_table / sizeof *lookup_table; for(int i=0; i!= available_snacks; i++) if( strcmp( snack, lookup_table[i]) == 0 ) return i; return ITEM_NONE; } int main() { char* input; printf("Enter the snack's name: "); scanf("%s", input); switch ( lookup(input) ) { case ITEM_CRISPS: printf("Walkers Cheese & Onion\n"); break; case ITEM_CHOCOLATE: printf("Cadburys Dairy Milk\n"); break; case ITEM_LEMONADE: printf("Schweppes Lemonade\n"); break; case ITEM_BISCUITS: printf("McVities Digestives\n"); break; default: printf("Invalid selection\n"); } return 0; }
In summary
There's nothing stopping this method being adapted for Python, C++, Java, or any other language, However, other languages could make this program far simpler through the use of their own container libraries to handle Strings, Arrays and Search algorithms (for example C++ has std::string, std::vector and std::find ).
The real focus of this tutorial should show how versatile the concept of lookup tables can be when associating the program's behaviour with different data values, regardless of their type. Extending the capabilities of a switch statement is only one limited use for this technique. Selection can be fairly long and unweildy - in this example, it would be possible to remove the selection process entirely using lookups from data structures, however, that extends beyond the scope of this tutorial.
Last edited by happygeek; Dec 20th, 2006 at 5:26 am. Reason: formatting
This is a very bad no-no:
This is C++ or C99:
I'd recommend cleaning these up and making it C90 if it's aimed at a C audience. Because this code first failed to compile for me, and then repeatedly crashed (not good in a tutorial).
Also, using
char* input; printf("Enter the snack's name: "); scanf("%s", input);
int lookup(char snack[])
{
convert_lowercase(snack);
const int available_snacks = sizeof lookup_table / sizeof *lookup_table;
for(int i=0; i!= available_snacks; i++)Also, using
strlen as a loop condition is not recommended for performance reasons -- best not to get into the habit, and the usual idiom is < rather than != for safety reasons:for(i=0; i!=strlen(str); i++) "One of the methods used by statists to destroy capitalism consists in establishing controls that tie a given industry hand and foot, making it unable to solve its problems, then declaring that freedom has failed and stronger controls are necessary." --Ayn Rand
![]() |
Similar Threads
Other Threads in the C++ Forum
- Previous Thread: Writing to binary file, erases previous data?
- Next Thread: AnsiString to string conversion
Views: 6699 | Replies: 1
| Thread Tools | Search this Thread |
Tag cloud for C++
6 add api array arrays beginner binary c++ c/c++ calculator char class classes code compile compiler console conversion convert count data delete desktop directshow dll dynamic encryption error file forms fstream function functions game givemetehcodez google graph homeworkhelper iamthwee ifstream input int integer java lazy lib linkedlist linker linux loop looping loops map math matrix memory microsoft newbie news number output parameter pointer problem program programming project proxy python random read recursion recursive reference return sort stream string strings struct studio system template templates test text tree unix url variable vector video visual visualstudio win32 windows winsock word wordfrequency wxwidgets






