can we use switch-case statement with strings in c? [duplicate] - c

This question already has answers here:
How can I compare strings in C using a `switch` statement?
(16 answers)
Closed 5 years ago.
int a = 0 , b = 0;
char* c = NULL;
int main(int argc , char ** argv){
c = argv[2];
a = atoi(argv[1]);
b = atoi(argv[3]);
switch(c){
case "+": printf(a+b);
break;
}
printf("\n\n");
return 0;
}

No, you can't. Switch is intended to compare numeric types, and for extension char types.
Instead you should use the strcmp function, included in string header:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc != 4) {
puts("Incorrect usage");
return 1;
}
/* You should check the number of arguments */
char * op = argv[1];
int a = atoi(argv[2]);
int b = atoi(argv[3]);
/* You should check correct input too */
if (strcmp(op, "+") == 0)
printf("%d + %d = %d\n", a, b, a + b);
else if (strcmp(op, "-") == 0)
printf("%d - %d = %d\n", a, b, a - b);
/* Add more functions here */
return 0;
}

No you can't. The case labels of a switch need to be compile time evaluable constant expressions with an integral type.
But int literals like '+' satisfy that requirement. (As do enum values for that matter.)
Some folk like to use implementation-defined multi-character literals (e.g. 'eax') as case labels as they claim it helps readability, but at that point, you're giving up consistent behaviour across different platforms.
If you need to branch on the value of a NUL-terminated char array, then use an if block.

There are two cases to the answer ..
Firstly 6.8.4.2 (switch case)
The controlling expression of a switch statement shall have integer
type
Secondly 6.8.4.2 (the case statements)
The expression of each case label shall be an integer constant
expression and no two of the case constant expressions in the same
switch statement shall have the same value after conversion
Long story short - you can't use string literal like that. Neither in switch controlling expression nor in case.
You can do the string comparisons using strcmp and then do the if-else conditioning. The context on which you ask this, you can simply pass the character + (argv[2][0]) instead of passing the whole literal. That way you will be passing char to the switch expression and then work accordingly.

Nope, that's not possible.
Quoting C11, chapter §6.8.4.2
The controlling expression of a switch statement shall have integer type.

in your case, you don't seem to need a string but rather the first (and only character) of the string passed in the switch statement, in that case that's possible using character literal (which has integer type) in the case statements:
if (strlen(c)==1)
{
switch(c[0]){
case '+': printf(a+b);
break;
...
}
}
some good other alternatives are described in best way to switch on a string in C when the string has multiple characters.

Not directly. But yes, you can.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// The way you store and search for names is entirely
// up to you. This is a simple linear search of an
// array. If you have a lot of names, you might choose
// a better storage + lookup, such as a hash table.
int find( const char** ss, int n, const char* s )
{
int i = 0;
while (i < n)
if (strcmp( ss[i], s ) == 0) break;
else i += 1;
return i;
}
// A bevvy of little utilities to help out.
char* strupper( char* s )
{
char* p = s;
while ((*p = toupper( *p ))) ++p;
return s;
}
char* zero( char* p ) { if (p) *p = 0; return p; }
#define STRINGIFY(S) STRINGIFY0(S)
#define STRINGIFY0(S) #S
int main()
{
// Our list of names are enumerated constants with associated
// string data. We use the Enum Macro Trick for succinct ODR happiness.
#define NAMES(F) \
F(MARINETTE) \
F(ADRIAN) \
F(ALYA) \
F(DINO)
#define ENUM_F(NAME) NAME,
#define STRING_F(NAME) STRINGIFY(NAME),
enum names { NAMES(ENUM_F) NUM_NAMES };
const char* names[ NUM_NAMES ] = { NAMES(STRING_F) NULL };
#undef STRING_F
#undef ENUM_F
#undef NAMES
// Ask user for a name
char s[ 500 ];
printf( "name? " );
fflush( stdout );
fgets( s, sizeof( s ), stdin );
zero( strchr( s, '\n' ) );
// Preprocess and search for the name
switch (find( names, sizeof(names)/sizeof(*names), strupper( s ) ))
{
case MARINETTE: puts( "Ladybug!" ); break;
case ADRIAN: puts( "Chat Noir!" ); break;
case ALYA:
case DINO: puts( "Best friend!" ); break;
default: puts( "Who?" );
}
}
Keep in mind this works by pure, unadulterated magic tricks, and is not suitable for large collections of text values.
Also, the validity of the match is entirely dependent on the degree to which you pre-process the user’s input. In this example we only ignore case, but a more advanced application might perform some more sophisticated matching.

As others pointed out in C one cannot use a string as argument to a switch, nor to its case-labels.
To get around this limitation one could map each string to a specific integer and pass this to the switch.
Looking up the mapping requires searching the map, which can be done using the Standard C bsearch() function.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int cmp(const void * pv1, const void * pv2)
{
const struct Operation_Descriptor * pop1 = pv1;
const struct Operation_Descriptor * pop2 = pv2;
return strcmp(pop1->name, pop2->name);
}
int main(int argc, char ** argv)
{
size_t s = sizeof operations / sizeof *operations;
/* bsearch() requires the array to search to be sorted. */
qsort(operations, s, sizeof *operations, cmp);
{
struct Operation_Descriptor * pop =
bsearch(
&(struct Operation_Descriptor){argv[1], OP_INVALID},
operations, s, sizeof *operations, cmp);
switch(pop ?pop->op :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
}
If on POSIX one can even use a hash table, which is the fastest way to lookup the mapping.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int main(int argc, char ** argv)
{
if (0 == hcreate(5))
{
perror("hcreate() failed");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < s; ++i)
{
if (!hsearch((ENTRY){operations[i].name, &operations[i].op}, ENTER))
{
perror("hsearch(ENTER) failed");
exit(EXIT_FAILURE);
}
}
{
ENTRY * ep = hsearch((ENTRY){argv[1], NULL}, FIND);
switch(ep ?*((enum Operation *)ep->data) :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
hdestroy(); /* Clean up. */
}

Related

(C) Am I properly converting enum type to string?

I am very new to coding, and am taking an online course with very little help. I am working through an assignment creating a bunch of functions that will be used at a later date. I have not learned anything about points, arrays, or recursions at this point. My knowledge of strings is pretty much limited to the "printf" function.
With that being said, I have been given this description for how the function "ranking_to_string" should operate:
This function should convert the
hand_ranking_t enumerated value passed
in to a string that describes it.
The enumerated type here is hand_ranking_t, which ranks a poker hand in descending order of value from STRAIGHT_FLUSH (0) to NOTHING (8). With that all being said, this is the function I have created to attempt to follow my instructions:
const char * ranking_to_string(hand_ranking_t r) {
switch (r) {
case STRAIGHT_FLUSH: printf("STRAIGHT_FLUSH\n"); break;
case FOUR_OF_A_KIND: printf("FOUR_OF_A_KIND\n"); break;
case FULL_HOUSE: printf("FULL_HOUSE\n"); break;
case FLUSH: printf("FLUSH\n"); break;
case STRAIGHT: printf("STRAIGHT\n"); break;
case THREE_OF_A_KIND: printf("THREE_OF_A_KIND\n"); break;
case TWO_PAIR: printf("TWO_PAIR\n"); break;
case PAIR: printf("PAIR\n"); break;
case NOTHING: printf("NOTHING\n"); break;
default: printf("Invalid thing\n"); break;
}
return EXIT_SUCCESS;
}
I am wondering, am I correct in returning EXIT_SUCCESS (0) at the end of the function? Is there another way to convert the enum value entered into a string using printf?
EXIT_SUCCESS is a macro that will expand into an environment defined indicator to be returned from main (or via exit, etc.) to indicate that your entire program has successfully done what it is supposed to do. It's generally not used outside this context.
printf is used to send output to the stream associated with stdout. For example, you might call printf to display text in your terminal.
Your function should instead return the string literals, to be used by the caller of ranking_to_string.
const char *ranking_to_string(hand_ranking_t r) {
switch (r) {
case STRAIGHT_FLUSH: return "STRAIGHT_FLUSH";
case FOUR_OF_A_KIND: return "FOUR_OF_A_KIND";
/* ... and so on ... */
default: return "Invalid thing";
}
}
An example program:
#include <stdio.h>
typedef enum {
STRAIGHT_FLUSH,
FOUR_OF_A_KIND,
/* ... and so on ... */
} hand_ranking_t;
const char *ranking_to_string(hand_ranking_t r) {
switch (r) {
case STRAIGHT_FLUSH: return "STRAIGHT_FLUSH";
case FOUR_OF_A_KIND: return "FOUR_OF_A_KIND";
/* ... and so on ... */
default: return "Invalid thing";
}
}
int main(void) {
hand_ranking_t rank = FOUR_OF_A_KIND;
const char *rank_string = ranking_to_string(rank);
printf("My ranking is <%s>\n", rank_string);
}
Output:
My ranking is <FOUR_OF_A_KIND>
Probably not covered in your course, but it's possible to automate ranking_to_string entirely by using X-Macros. Also, since poker hands have value, it makes sense to list them by it.
#include <stdlib.h>
#include <stdio.h>
#define HANDS X(HIGH_CARD), X(PAIR), X(TWO_PAIR), X(THREE_OF_A_KIND), \
X(STRAIGHT), X(FLUSH), X(FULL_HOUSE), X(FOUR_OF_A_KIND), \
X(STRAIGHT_FLUSH), X(ROYAL_FLUSH)
#define X(name) name
enum hand { HANDS };
#undef X
#define X(name) #name
static const char *hand_str[] = { HANDS };
#undef X
static const size_t hand_size = sizeof hand_str / sizeof *hand_str;
int main(void) {
enum hand i, j;
for(i = 0; i < hand_size; i++) printf("%s\n", hand_str[i]);
i = FULL_HOUSE;
j = FLUSH;
printf("%s is %s than %s.\n",
hand_str[i], i < j ? "less" : "greater", hand_str[j]);
return EXIT_SUCCESS;
}
Where # is the stringizing operator of the pre-processor.

How can I print enum in C? [duplicate]

int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay;
int j = 0;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&j);
TheDay = Days(j);
//how to PRINT THE VALUES stored in TheDay
printf("%s",TheDay); // isnt working
return 0;
}
Enumerations in C are numbers that have convenient names inside your code. They are not strings, and the names assigned to them in the source code are not compiled into your program, and so they are not accessible at runtime.
The only way to get what you want is to write a function yourself that translates the enumeration value into a string. E.g. (assuming here that you move the declaration of enum Days outside of main):
const char* getDayName(enum Days day)
{
switch (day)
{
case Sunday: return "Sunday";
case Monday: return "Monday";
/* etc... */
}
}
/* Then, later in main: */
printf("%s", getDayName(TheDay));
Alternatively, you could use an array as a map, e.g.
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };
/* ... */
printf("%s", dayNames[TheDay]);
But here you would probably want to assign Sunday = 0 in the enumeration to be safe... I'm not sure if the C standard requires compilers to begin enumerations from 0, although most do (I'm sure someone will comment to confirm or deny this).
I use something like this:
in a file "EnumToString.h":
#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM
#ifndef GENERATE_ENUM_STRINGS
#define DECL_ENUM_ELEMENT( element ) element,
#define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
#define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
#define END_ENUM( ENUM_NAME ) ENUM_NAME; \
const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
#define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
switch( index ) {
#define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
#define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )
#define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;
#endif
then in any header file you make the enum declaration, day enum.h
#include "EnumToString.h"
BEGIN_ENUM(Days)
{
DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
DECL_ENUM_ELEMENT(Monday) //will render "Monday"
DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
/* ... and so on */
}
END_ENUM(MyEnum)
then in a file called EnumToString.c:
#include "enum.h"
#define GENERATE_ENUM_STRINGS // Start string generation
#include "enum.h"
#undef GENERATE_ENUM_STRINGS // Stop string generation
then in main.c:
int main(int argc, char* argv[])
{
Days TheDay = Monday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"
TheDay = Thursday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"
return 0;
}
this will generate "automatically" the strings for any enums declared this way and included in "EnumToString.c"
The way I usually do this is by storing the string representations in a separate array in the same order, then indexing the array with the enum value:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"
enums in C don't really work the way you're expecting them to. You can think of them kind of like glorified constants (with a few additional benefits relating to being a collection of such constants), and the text you've written in for "Sunday" really gets resolved to a number during compilation, the text is ultimately discarded.
In short: to do what you really want you'll need to keep an array of the strings or create a function to map from the enum's value to the text you'd like to print.
Enumerations in C are basically syntactical sugar for named lists of automatically-sequenced integer values. That is, when you have this code:
int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay = Monday;
}
Your compiler actually spits out this:
int main()
{
int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}
Therefore, outputting a C enumeration as a string is not an operation that makes sense to the compiler. If you want to have human-readable strings for these, you will need to define functions to convert from enumerations to strings.
Here's a cleaner way to do it with macros:
#include <stdio.h>
#include <stdlib.h>
#define DOW(X, S) \
X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)
#define COMMA ,
/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
DOW(DOW_ENUM, COMMA)
};
/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
DOW(DOW_ARR, COMMA)
};
/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D
switch(i) {
DOW(DOW_CASE, ;);
default: return NULL;
}
}
int main(void)
{
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dow_str[i]);
printf("\n");
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dowstr(i));
return 0;
}
I'm not sure that this is totally portable b/w preprocessors, but it works with gcc.
This is c99 btw, so use c99 strict if you plug it into (the online compiler) ideone.
I know I am late to the party, but how about this?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"
This way, you do not have to manually keep the enum and the char* array in sync. If you are like me, chances are that you will later change the enum, and the char* array will print invalid strings.
This may not be a feature universally supported. But afaik, most of the mordern day C compilers support this designated initialier style.
You can read more about designated initializers here.
I like this to have enum in the dayNames.
To reduce typing, we can do the following:
#define EP(x) [x] = #x /* ENUM PRINT */
const char* dayNames[] = { EP(Sunday), EP(Monday)};
The question is you want write the name just one times.
I have an ider like this:
#define __ENUM(situation,num) \
int situation = num; const char * __##situation##_name = #situation;
const struct {
__ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write,
__ENUM(get_negative_to_unsigned, -204);
__ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
int get_no_num = -201; const char * __get_no_num_name = "get_no_num";
int get_float_to_int = -202; const char * get_float_to_int_name = "float_to_int_name";
}eRevJson;
#undef __ENUM
struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
inline const char * enumRevJsonGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
it uses a struct to insert enum, so that a printer to string could follows each enum value define.
int main(int argc, char *argv[]) {
int enum_test = eRevJson.get_other_string;
printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);
>error is get_other_string, number is -203
The difference to enum is builder can not report error if the numbers are repeated.
if you don't like write number, __LINE__ could replace it:
#define ____LINE__ __LINE__
#define __ENUM(situation) \
int situation = (____LINE__ - __BASELINE -2); const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
__ENUM(Sunday);
__ENUM(Monday);
__ENUM(Tuesday);
__ENUM(Wednesday);
__ENUM(Thursday);
__ENUM(Friday);
__ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
int main(int argc, char *argv[]) {
int d = eDays.Wednesday;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
d = 1;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
}
>day Wednesday, number is 3 >day Monday, number is 1
There is another solution: Create your own dynamic enumeration class. Means you have a struct and some function to create a new enumeration, which stores the elements in a struct and each element has a string for the name. You also need some type to store a individual elements, functions to compare them and so on.
Here is an example:
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Enumeration_element_T
{
size_t index;
struct Enumeration_T *parent;
char *name;
};
struct Enumeration_T
{
size_t len;
struct Enumeration_element_T elements[];
};
void enumeration_delete(struct Enumeration_T *self)
{
if(self)
{
while(self->len--)
{
free(self->elements[self->len].name);
}
free(self);
}
}
struct Enumeration_T *enumeration_create(size_t len,...)
{
//We do not check for size_t overflows, but we should.
struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len);
if(!self)
{
return NULL;
}
self->len=0;
va_list l;
va_start(l,len);
for(size_t i=0;i<len;i++)
{
const char *name=va_arg(l,const char *);
self->elements[i].name=malloc(strlen(name)+1);
if(!self->elements[i].name)
{
enumeration_delete(self);
return NULL;
}
strcpy(self->elements[i].name,name);
self->len++;
}
return self;
}
bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b)
{
return a->parent==b->parent && a->index==b->index;
}
bool enumeration_isName(struct Enumeration_element_T *a, const char *name)
{
return !strcmp(a->name,name);
}
const char *enumeration_getName(struct Enumeration_element_T *a)
{
return a->name;
}
struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name)
{
for(size_t i=0;i<self->len;i++)
{
if(enumeration_isName(&self->elements[i],name))
{
return &self->elements[i];
}
}
return NULL;
}
struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index)
{
return &self->elements[index];
}
size_t enumeration_getCount(struct Enumeration_T *self)
{
return self->len;
}
bool enumeration_isInRange(struct Enumeration_T *self, size_t index)
{
return index<self->len;
}
int main(void)
{
struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
if(!weekdays)
{
return 1;
}
printf("Please enter the day of the week (0 to 6)\n");
size_t j = 0;
if(scanf("%zu",&j)!=1)
{
enumeration_delete(weekdays);
return 1;
}
// j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range
if(!enumeration_isInRange(weekdays,j))
{
enumeration_delete(weekdays);
return 1;
}
struct Enumeration_element_T *day=enumeration_get(weekdays,j);
printf("%s\n",enumeration_getName(day));
enumeration_delete(weekdays);
return 0;
}
The functions of enumeration should be in their own translation unit, but i combined them here to make it simpler.
The advantage is that this solution is flexible, follows the DRY principle, you can store information along with each element, you can create new enumerations during runtime and you can add new elements during runtime.
The disadvantage is that this is complex, needs dynamic memory allocation, can't be used in switch-case, needs more memory and is slower. The question is if you should not use a higher level language in cases where you need this.
Using a Macro and stringize operator(#) we can achieve this....
#include <stdio.h>
typedef enum
{
MON=0,
TUE
}week;
int main()
{
#define printt(data) printf("%s",#data);
printt(MON);
return 0;
}
i'm new to this but a switch statement will defenitely work
#include <stdio.h>
enum mycolor;
int main(int argc, const char * argv[])
{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};
enum Days TheDay;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&TheDay);
switch (TheDay)
{
case Sunday:
printf("the selected day is sunday");
break;
case Monday:
printf("the selected day is monday");
break;
case Tuesday:
printf("the selected day is Tuesday");
break;
case Wednesday:
printf("the selected day is Wednesday");
break;
case Thursday:
printf("the selected day is thursday");
break;
case Friday:
printf("the selected day is friday");
break;
case Saturday:
printf("the selected day is Saturaday");
break;
default:
break;
}
return 0;
}
TheDay maps back to some integer type. So:
printf("%s", TheDay);
Attempts to parse TheDay as a string, and will either print out garbage or crash.
printf is not typesafe and trusts you to pass the right value to it. To print out the name of the value, you'd need to create some method for mapping the enum value to a string - either a lookup table, giant switch statement, etc.

Switch statement using string on an array

#include<stdio.h>
int main(){
char name[20];
printf("enter a name ");
scanf("%s",name);
switch(name[20]){
case "kevin" :
printf("hello");
break;
}
printf("%s",name);
getch();
}
It seems it will not work. Is this possible? I mean is there any way we can make a switch statement of a string. How to solve the problem, actually?
Switch statements in C aren't smart like one's found in other languages (such as Java 7 or Go) you cannot switch on a string (Nor can you compare strings with ==). Switch can only operate on integral types (int, char, etc).
In your code you call switch with: switch(name[20]). That means switch(*(name + 20)). In other words switch on the 21st char in name (because name[0] is the first). As name only has 20 chars you are accessing whatever memory is after name. (which could do unpredictable things)
Also the string "kevin" is compiled to a char[N] (where N is strlen("kevin") + 1) which contains the string. When you do case "kevin". It will only work if name is in the exact same piece of memory storing the string. So even if I copied kevin into name. It still would not match as it is stored in a different piece of memory.
To do what you seem to be trying you would do this:
#include <string.h>
...
if (strcmp(name, "kevin") == 0) {
...
}
String compare (strcmp) returns different values based on the difference in the strings. Eg:
int ord = strcmp(str1, str2);
if (ord < 0)
printf("str1 is before str2 alphabetically\n");
else if (ord == 0)
printf("str1 is the same as str2\n");
else if (ord > 0)
printf("str1 is after str2 alphabetically\n");
Side note: Dont use scanf("%s", name) in that form. It creates a common security problem use fgets like this: (there is a safe way to use scanf too)
#define MAX_LEN 20
int main() {
char name[MAX_LEN];
fgets(name, MAX_LEN, stdin);
...
Switch statements work on int values (or enum), but not on char arrays.
You could do
if (strcmp(name, "kevin")==0) {
printf("hello");
}
else if (strcmp(name, "Laura")==0) {
printf("Allo");
}
else if (strcmp(name, "Mike")==0) {
printf("Good day");
}
else {
printf("Help!");
}
There are plenty of ways to go about this! For example, use a...
3-letter hash
#include <stdio.h>
int main(){
char name[20];
printf("enter a name ");
scanf("%s",name);
switch((int)*name * (int)*(name+1) * (int)*(name+2)){
case (1275226) : // "kevin"
printf("hello %s.\n", name);
break;
case (1293980) : // "astro"
printf("welcome %s.\n", name);
break;
}
printf("%d",(int)*name * (int)*(name+1) * (int)*(name+2));
}
No, you cannot use the switch statement in C with the value of a string or character array. The closest alternative is to use some sort of data structure mapping strings to function pointers. The function pointer could be called after a string is used to look it up.
since the name is declared as a char type ,it would be better if you use "%c" instead of using "%s" inside the scanf() method.
You can use "hash-string.h" library that converts strings into hash code integer.
Create a header file and paste this code:
http://www.opensource.apple.com/source/gcc/gcc-5484/intl/hash-string.h
#include <stdio.h>
#include <stdlib.h>
#include "hash-string.h"
int main(){
char name[20];
printf("Enter a name: ");
scanf("%s",name);
unsigned long nameInt = hash_string(name);
switch(nameInt){
case 7458046 /* "kevin" */: { printf("Hello %s", name); break; }
default: { printf("You are not kevin"); }
}
printf("\n");
return 0;
}
Remember the rules while using switch statements.
Switch constraints
1. The controlling expression of a switch statement must have "integer type".
2. The expression of each case label shall be an integer constant expression and no two of
the case constant expressions in the same switch statement shall have the same value
after conversion. There may be at most one default label in a switch statement.
3. Any enclosed switch statement may have a default label or case constant expressions with values that duplicate case constant expressions in the enclosing switch statement.
If you are after performing specific actions for specific strings this implies you know the strings in advance. This in turn implies their number is limited, is countable, like for example a set of N commands:
const char * commands[] = {
"command-1",
"command-2",
...
"command-N"
}
To address those commands inside the array above from your code using a swtich you need to know their index, which is error prone. So number them, give them an ID:
enum Command_id {
NO_COMMAND,
COMMAND_1,
COMMAND_2,
//...
COMMAND_N,
};
Now put the two above together using a struct:
struct Command_info {
const char * command;
enum Command_id id;
} command_infos[] = {
{"", NO_COMMAND},
{"command-1", COMMAND_1},
{"command-2", COMMAND_2},
// ...
{"command-N", COMMAND_N},
};
Now you have nice mapping of strings and their related IDs. To be able to map from string to ID during runtime the mapping above needs to be searched. To do this in a efficient manner you want to us binary search. The C library proveids bsearch() for this. The only prerequsite is that the array to be searched need to sorted.
To sort use qsort() also proveid by the C library. For qsort() to work we you need a comparsion function:
int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
const struct Command_info * pCI1 = pvCI1;
const struct Command_info * pCI2 = pvCI2;
return strcmp(pCI1->command, pCI2->command);
}
Call qsort() like this
qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
Now as the array is sorted one can look it up using bsearch(). For "COMMAND-2" this would look like this:
... = bsearch(&(struct Command_info){"COMMAND-2", NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
Putting all this together could result in:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
enum Command_id {
NO_COMMAND,
COMMAND_1,
COMMAND_2,
//...
COMMAND_N,
};
struct Command_info {
const char * command;
enum Command_id id;
} command_infos[] = {
{"", NO_COMMAND},
{"command-1", COMMAND_1},
{"command-2", COMMAND_2},
// ...
{"command-N", COMMAND_N},
};
int cmp_command_infos(const void * pvCI1, const void* pvCI2)
{
const struct Command_info * pCI1 = pvCI1;
const struct Command_info * pCI2 = pvCI2;
return strcmp(pCI1->command, pCI2->command);
}
int main(int argc, char ** argv)
{
qsort(command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
{
enum Command_id command_id = NO_COMMAND;
struct Command_info * pCI = bsearch(&(struct Command_info){argv[1], NO_COMMAND}, command_infos, sizeof command_infos / sizeof *command_infos, sizeof *command_infos, cmp_command_infos);
if (NULL == pCI)
{
printf("Command = '%s' is unknown\n", argv[1]);
}
else
{
printf("Command = '%s' --> ID = %d\n", pCI->command, pCI->id);
switch(command_id)
{
case COMMAND_1:
/* perform action on COMMAND 1 here */
break;
case COMMAND_2:
/* perform action on COMMAND 1 here */
break;
default:
/* unknow command, do nothing */
break;
}
}
}
}
Call it like:
./a.out command-1
giving:
Command = 'command-1' --> ID = 1
or:
./a.out command-bla
giving:
Command = 'command-bla' is unknown
or even
./a.out ""
giving:
Command = '' --> ID = 0

how to best achieve string to number mapping in a c program

I have a definite set of strings and its corresponding numbers:
kill -> 1
live -> 2
half_kill -> 3
dont_live -> 4
List is of 30 such strings and their number mapping.
If user enters "kill", I need to return 1 and if he enters "dont_live" I need to return 4.
How should I achieve this in c program? I am looking for an efficient solution because this operation needs to be done 100s of times.
should I put them in #define in my .h file?
Thanks in advance.
Sort your table, and use the standard library function bsearch to perform a binary search.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct entry {
char *str;
int n;
};
/* sorted according to str */
struct entry dict[] = {
"dont_live", 4,
"half_kill", 3,
"kill", 1,
"live", 2,
};
int compare(const void *s1, const void *s2)
{
const struct entry *e1 = s1;
const struct entry *e2 = s2;
return strcmp(e1->str, e2->str);
}
int
main (int argc, char *argv[])
{
struct entry *result, key = {argv[1]};
result = bsearch(&key, dict, sizeof(dict)/sizeof(dict[0]),
sizeof dict[0], compare);
if (result)
printf("%d\n", result->n);
return 0;
}
Here's what you get when you run the program.
$ ./a.out kill
1
$ ./a.out half_kill
3
$ ./a.out foo
<no output>
PS: I reused portions of sidyll's program. My answer should now be CC BY-SA compliant :p
A possible solution:
#include <stdio.h>
#include <string.h>
struct entry {
char *str;
int n;
};
struct entry dict[] = {
"kill", 1,
"live", 2,
"half_kill", 3,
"dont_live", 4,
0,0
};
int
number_for_key(char *key)
{
int i = 0;
char *name = dict[i].str;
while (name) {
if (strcmp(name, key) == 0)
return dict[i].n;
name = dict[++i].str;
}
return 0;
}
int
main (int argc, char *argv[])
{
printf("enter your keyword: ");
char s[100]; scanf("%s", s);
printf("the number is: %d\n", number_for_key(s));
return 0;
}
Here's one approach:
int get_index(char *s)
{
static const char mapping[] = "\1.kill\2.live\3.half_kill\4.dont_live";
char buf[sizeof mapping];
const char *p;
snprintf(buf, sizeof buf, ".%s", s);
p = strstr(mapping, buf);
return p ? p[-1] : 0;
}
The . mess is to work around kill being a substring of half_kill. Without that issue you could simply search for the string directly.
If it is a very short list of strings then a simple block of ifs will be more than sufficient
if (0 == strcmp(value, "kill")) {
return 1;
}
if (0 == strcmp(value, "live")) {
return 2;
}
...
If the number approach 10 I would begin to profile my application though and consider a map style structure.
if you have a fixed set of strimgs, you have two options: generate a perfect hashing function (check gperf or cmph) or create a trie so that you never have to check charcters more than once.
Compilers usually use perfect hashes to recognize a language keyword, in your case I would probably go with the trie, it should be the fastest way (but nothing beats direct measurement!)
Is it really a bottleneck? You should worry about efficiency only if the simple solution proves to be too slow.
Having said that, possible speed improvements are checking the lengths first:
If it's 4 characters then it could be "kill" or "live"
If it's 9 characters then it could be "half_kill" or "dont_live"
or checking the first character in a switch statement:
switch (string[0]) {
case 'k':
if (strcmp(string, "kill") == 0)
return 1;
return 0;
case 'l':
...
default:
return 0;
}
Use hashmap/ hashtable i think this would be the best solution.
Can you use an Enumunerator?
int main(void) {
enum outcome { kill=1, live, half_kill, dont_live };
printf("%i\n", kill); //1
printf("%i\n", dont_live); //4
printf("%i\n", half_kill); //3
printf("%i\n", live); //2
return 0;
}
Create a list of const values:
const int kill = 1;
const int live = 2;
const int half_kill = 3;
etc

Print text instead of value from C enum

int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay;
int j = 0;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&j);
TheDay = Days(j);
//how to PRINT THE VALUES stored in TheDay
printf("%s",TheDay); // isnt working
return 0;
}
Enumerations in C are numbers that have convenient names inside your code. They are not strings, and the names assigned to them in the source code are not compiled into your program, and so they are not accessible at runtime.
The only way to get what you want is to write a function yourself that translates the enumeration value into a string. E.g. (assuming here that you move the declaration of enum Days outside of main):
const char* getDayName(enum Days day)
{
switch (day)
{
case Sunday: return "Sunday";
case Monday: return "Monday";
/* etc... */
}
}
/* Then, later in main: */
printf("%s", getDayName(TheDay));
Alternatively, you could use an array as a map, e.g.
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };
/* ... */
printf("%s", dayNames[TheDay]);
But here you would probably want to assign Sunday = 0 in the enumeration to be safe... I'm not sure if the C standard requires compilers to begin enumerations from 0, although most do (I'm sure someone will comment to confirm or deny this).
I use something like this:
in a file "EnumToString.h":
#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM
#ifndef GENERATE_ENUM_STRINGS
#define DECL_ENUM_ELEMENT( element ) element,
#define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
#define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
#define END_ENUM( ENUM_NAME ) ENUM_NAME; \
const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
#define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
switch( index ) {
#define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
#define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )
#define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;
#endif
then in any header file you make the enum declaration, day enum.h
#include "EnumToString.h"
BEGIN_ENUM(Days)
{
DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
DECL_ENUM_ELEMENT(Monday) //will render "Monday"
DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
/* ... and so on */
}
END_ENUM(MyEnum)
then in a file called EnumToString.c:
#include "enum.h"
#define GENERATE_ENUM_STRINGS // Start string generation
#include "enum.h"
#undef GENERATE_ENUM_STRINGS // Stop string generation
then in main.c:
int main(int argc, char* argv[])
{
Days TheDay = Monday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"
TheDay = Thursday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"
return 0;
}
this will generate "automatically" the strings for any enums declared this way and included in "EnumToString.c"
The way I usually do this is by storing the string representations in a separate array in the same order, then indexing the array with the enum value:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"
enums in C don't really work the way you're expecting them to. You can think of them kind of like glorified constants (with a few additional benefits relating to being a collection of such constants), and the text you've written in for "Sunday" really gets resolved to a number during compilation, the text is ultimately discarded.
In short: to do what you really want you'll need to keep an array of the strings or create a function to map from the enum's value to the text you'd like to print.
Enumerations in C are basically syntactical sugar for named lists of automatically-sequenced integer values. That is, when you have this code:
int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay = Monday;
}
Your compiler actually spits out this:
int main()
{
int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}
Therefore, outputting a C enumeration as a string is not an operation that makes sense to the compiler. If you want to have human-readable strings for these, you will need to define functions to convert from enumerations to strings.
Here's a cleaner way to do it with macros:
#include <stdio.h>
#include <stdlib.h>
#define DOW(X, S) \
X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)
#define COMMA ,
/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
DOW(DOW_ENUM, COMMA)
};
/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
DOW(DOW_ARR, COMMA)
};
/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D
switch(i) {
DOW(DOW_CASE, ;);
default: return NULL;
}
}
int main(void)
{
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dow_str[i]);
printf("\n");
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dowstr(i));
return 0;
}
I'm not sure that this is totally portable b/w preprocessors, but it works with gcc.
This is c99 btw, so use c99 strict if you plug it into (the online compiler) ideone.
I know I am late to the party, but how about this?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"
This way, you do not have to manually keep the enum and the char* array in sync. If you are like me, chances are that you will later change the enum, and the char* array will print invalid strings.
This may not be a feature universally supported. But afaik, most of the mordern day C compilers support this designated initialier style.
You can read more about designated initializers here.
I like this to have enum in the dayNames.
To reduce typing, we can do the following:
#define EP(x) [x] = #x /* ENUM PRINT */
const char* dayNames[] = { EP(Sunday), EP(Monday)};
The question is you want write the name just one times.
I have an ider like this:
#define __ENUM(situation,num) \
int situation = num; const char * __##situation##_name = #situation;
const struct {
__ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write,
__ENUM(get_negative_to_unsigned, -204);
__ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
int get_no_num = -201; const char * __get_no_num_name = "get_no_num";
int get_float_to_int = -202; const char * get_float_to_int_name = "float_to_int_name";
}eRevJson;
#undef __ENUM
struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
inline const char * enumRevJsonGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
it uses a struct to insert enum, so that a printer to string could follows each enum value define.
int main(int argc, char *argv[]) {
int enum_test = eRevJson.get_other_string;
printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);
>error is get_other_string, number is -203
The difference to enum is builder can not report error if the numbers are repeated.
if you don't like write number, __LINE__ could replace it:
#define ____LINE__ __LINE__
#define __ENUM(situation) \
int situation = (____LINE__ - __BASELINE -2); const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
__ENUM(Sunday);
__ENUM(Monday);
__ENUM(Tuesday);
__ENUM(Wednesday);
__ENUM(Thursday);
__ENUM(Friday);
__ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
int main(int argc, char *argv[]) {
int d = eDays.Wednesday;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
d = 1;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
}
>day Wednesday, number is 3 >day Monday, number is 1
There is another solution: Create your own dynamic enumeration class. Means you have a struct and some function to create a new enumeration, which stores the elements in a struct and each element has a string for the name. You also need some type to store a individual elements, functions to compare them and so on.
Here is an example:
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Enumeration_element_T
{
size_t index;
struct Enumeration_T *parent;
char *name;
};
struct Enumeration_T
{
size_t len;
struct Enumeration_element_T elements[];
};
void enumeration_delete(struct Enumeration_T *self)
{
if(self)
{
while(self->len--)
{
free(self->elements[self->len].name);
}
free(self);
}
}
struct Enumeration_T *enumeration_create(size_t len,...)
{
//We do not check for size_t overflows, but we should.
struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len);
if(!self)
{
return NULL;
}
self->len=0;
va_list l;
va_start(l,len);
for(size_t i=0;i<len;i++)
{
const char *name=va_arg(l,const char *);
self->elements[i].name=malloc(strlen(name)+1);
if(!self->elements[i].name)
{
enumeration_delete(self);
return NULL;
}
strcpy(self->elements[i].name,name);
self->len++;
}
return self;
}
bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b)
{
return a->parent==b->parent && a->index==b->index;
}
bool enumeration_isName(struct Enumeration_element_T *a, const char *name)
{
return !strcmp(a->name,name);
}
const char *enumeration_getName(struct Enumeration_element_T *a)
{
return a->name;
}
struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name)
{
for(size_t i=0;i<self->len;i++)
{
if(enumeration_isName(&self->elements[i],name))
{
return &self->elements[i];
}
}
return NULL;
}
struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index)
{
return &self->elements[index];
}
size_t enumeration_getCount(struct Enumeration_T *self)
{
return self->len;
}
bool enumeration_isInRange(struct Enumeration_T *self, size_t index)
{
return index<self->len;
}
int main(void)
{
struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
if(!weekdays)
{
return 1;
}
printf("Please enter the day of the week (0 to 6)\n");
size_t j = 0;
if(scanf("%zu",&j)!=1)
{
enumeration_delete(weekdays);
return 1;
}
// j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range
if(!enumeration_isInRange(weekdays,j))
{
enumeration_delete(weekdays);
return 1;
}
struct Enumeration_element_T *day=enumeration_get(weekdays,j);
printf("%s\n",enumeration_getName(day));
enumeration_delete(weekdays);
return 0;
}
The functions of enumeration should be in their own translation unit, but i combined them here to make it simpler.
The advantage is that this solution is flexible, follows the DRY principle, you can store information along with each element, you can create new enumerations during runtime and you can add new elements during runtime.
The disadvantage is that this is complex, needs dynamic memory allocation, can't be used in switch-case, needs more memory and is slower. The question is if you should not use a higher level language in cases where you need this.
Using a Macro and stringize operator(#) we can achieve this....
#include <stdio.h>
typedef enum
{
MON=0,
TUE
}week;
int main()
{
#define printt(data) printf("%s",#data);
printt(MON);
return 0;
}
i'm new to this but a switch statement will defenitely work
#include <stdio.h>
enum mycolor;
int main(int argc, const char * argv[])
{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};
enum Days TheDay;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&TheDay);
switch (TheDay)
{
case Sunday:
printf("the selected day is sunday");
break;
case Monday:
printf("the selected day is monday");
break;
case Tuesday:
printf("the selected day is Tuesday");
break;
case Wednesday:
printf("the selected day is Wednesday");
break;
case Thursday:
printf("the selected day is thursday");
break;
case Friday:
printf("the selected day is friday");
break;
case Saturday:
printf("the selected day is Saturaday");
break;
default:
break;
}
return 0;
}
TheDay maps back to some integer type. So:
printf("%s", TheDay);
Attempts to parse TheDay as a string, and will either print out garbage or crash.
printf is not typesafe and trusts you to pass the right value to it. To print out the name of the value, you'd need to create some method for mapping the enum value to a string - either a lookup table, giant switch statement, etc.

Resources