0

code is here!

I tried to get the value of enum value as string from the user input and want to decode the value and print the case according to it, using Switch case but can't decode the exact value.

enum design {E2F = 1, E2, E3, E4, E5};    char *designation[5];

If someone helps I will be happy

Thanks.

2 Answers2

1

An enum maps symbols to numbers. Here are the 3 options we discussed:

  1. If you want to map strings to numbers use a struct:

    struct {
      const char *design;
      int value;
    } designs[] = {
      {"E2F", 1},
      {"E2", 2},
      {"E3", 3}
      {"E4", 4},
      {"E5", 5}
    };
    
  2. If you want the struct defined in terms of the enum. Generate both from the same data (DESIGNS):

     #define DESIGNS\
     _(E2F, 1)\
     _(E2, 2)\
     _(E3, 3)\
     _(E4, 4)\
     _(E5, 5)
    
     #define _(A, B) A = B,
     enum {
       DESIGNS
     };
    
     #undef _
     #define _(A, B) { #A, A },
     struct {
       const char *design;
       int value;
     } designs[] = {
       DESIGNS
     };
    

which the pre-processor would expand to:

    enum {
      E2F = 1, E2 = 2, E3 = 3, E4 = 4, E5 = 5,
    };

    struct {
      const char *design;
      int value;
    } designs[] = {
      { "E2F", E2F }, { "E2", E2 }, { "E3", E3 }, { "E4", E4 }, { "E5", E5 },
    };
  1. And here is @DavidCRankin's suggestion (if I understood it right) to just store the array to derive the value from the index:

     #include <string.h>
    
     int design_to_number(const char *str) {
       const char *designs[] = { "E2F", "E2", "E3", "E4", "E5" };
       for(int i = 0; i < sizeof(designs) / sizeof(*designs); i++) {
         if(!strcmp(designs[i], str)) return i + 1;
       }
       return -1;
     }
    
Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • This means you need to synchronize the struct and enum. You can generate both from the same data though. – Allan Wind Dec 27 '20 at 07:16
  • The X-macro approach doesn't provide a way to check the end of the list (or a sentinel), OP wants to search from a string, how do you know when to stop scanning/searching? I will use something like something like https://ideone.com/PvhmPv – David Ranieri Dec 27 '20 at 07:40
  • sizeof(array)/sizeof(*array) gives you the size of the array so you don't need a sentinel. – Allan Wind Dec 27 '20 at 07:45
  • @AllanWind yes, is an option, good point! – David Ranieri Dec 27 '20 at 07:49
0

C enum values are just named integers. For string conversion, you'll need to roll our own (unlike Java, for example, where enums are more powerful). One way to go about conversion from string to enum is use the library bsearch function:

#include <stdlib.h>
#include <assert.h>
#include <string.h>

enum design {E2F = 1, E2, E3, E4, E5};

struct design_value {
  const char *design;
  enum design value;
} designs[] = {
  {"E2", E2},
  {"E2F", E2F},
  {"E3", E3},
  {"E4", E4},
  {"E5", E5},
};

static int design_value_cmp(const void *a, const void *b) {
  return strcmp(((struct design_value*) a)->design, ((struct design_value*) b)->design);
}

enum design get_design(char *designation) {
  struct design_value key[1] = {{ designation }};
  struct design_value *result = (struct design_value*) bsearch(
    key, 
    designs, sizeof designs / sizeof designs[0], sizeof designs[0], 
    design_value_cmp);
  assert(result);
  return result->value;
}

// Tiny verifier. Don't use scanf("%s"...) in real code.
#include <stdio.h>

int main(void) {
  char buf[100];
  scanf("%s", buf);
  printf("%d\n", get_design(buf));
  return 0;
}

Note bsearch requires that the strings be in alpha order.

Gene
  • 46,253
  • 4
  • 58
  • 96
  • `bsearch` seems a bit of over kill. Why not just use a for loop to look for it? – Ed Heal Dec 27 '20 at 08:01
  • 1
    bsearch implies a sorted array, and you have done that by hand. It would probably be better to allow user to specify the data in it's natural order and then have the program sort it. This also eliminates programmer incorrectly sorted data. bsearch is O(log n) but usually not faster till n > 1000 or so (depends on hardware, but n is surprisingly large in practice). I think it's great to have another solution. – Allan Wind Dec 27 '20 at 08:01
  • @AllanWind - I agree - `bsearch` is probably slower for small number of items – Ed Heal Dec 27 '20 at 08:07
  • https://stackoverflow.com/questions/1621394/how-to-prevent-scanf-causing-a-buffer-overflow-in-c has some suggestions re overflow in scanf. – Allan Wind Dec 27 '20 at 08:14
  • i.e. use scanf("%100s, ...), fgets or read – Allan Wind Dec 27 '20 at 08:24
  • I added the tiny driver to make it a mcve for `get_design`. `bsearch` is a future-proof choice. Not "overkill" at all. `gcc` inlines it (including the comparison function and generates only _20_ x86 instructions for the body of `get_design`. I've seen enums in production that grew slowly to over 50,000 values. – Gene Dec 28 '20 at 15:50