How to get the value of enum from a string - c

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.

An enum maps symbols to numbers. Here are the 3 options we discussed:
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}
};
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 },
};
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;
}

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.

Related

Accessing struct array using double pointers in c

typedef enum
{
ONE = 1,
TWO = 2,
THREE = 3
}Count_t;
typedef enum
{
RED = 0,
BLUE = 1,
GREEN = 2
}Color_t;
typedef struct
{
Count_t Count_en;
Color_t Color_en;
}Grp_t;
Grp_t const Grp_ena[]=
{
{ ONE, RED },
{ TWO, BLUE },
{ THREE, GREEN}
};
typedef struct
{
unsigned int num;
Grp_t * Grp_stp;
}Try_t;
Try_t const Try_sta[] =
{
{ 7, &Grp_ena[0] },
{ 8, &Grp_ena[1] },
{ 9, &Grp_ena[2] },
};
int main()
{
Try_t **p = Try_sta;
}
Using double pointer **p , I want to access the elements of LUT Try_sta. With single dimensional pointer I am able to access the struct array elements. But with 2d pointer I failed to access. Is there any proper way to do it?

How to sort array of structs by char field so that empty fields go to last place?

I have a struct:
struct StructA{
char name[TEXT_LEN];
int year;
};
typedef struct StructA Data_t;
And lets say that it can be something like:
Name: A
Year: 2002
Name:
Year: 2003
Name: C
Year: 2003
Name: B
Year: 2004
Name:
Year: 2005
Now I would like to sort it in a way that it sorts first existing values and put empty values in last place. For this I use qsort():
int compareDataT(const void *v1, const void *v2)
{
const Data_t *u1 = v1;
const Data_t *u2 = v2;
return strcmp(u1->name, u2->name);
}
qsort(items, length, sizeof(Data_t), compareDataT);
This gives me:
Name:
Year: 2003
Name:
Year: 2005
Name: A
Year: 2002
Name: B
Year: 2004
Name: C
Year: 2003
If I reverse it in function then it gives me C, B, A, blank, blank...
I want to have it as A, B, C, blank, blank... So, sorted and then put blank values in the end.
I am struggling with this issue for hours... So any help is appreciated.
If you want the empty fields to go last, you can modify the comparison function so they compare larger than non empty ones:
int compareDataT(const void *v1, const void *v2) {
const Data_t *u1 = v1;
const Data_t *u2 = v2;
if (*u1->name == '\0')
return (*u2->name == '\0') ? 0 : 1;
if (*u2->name == '\0')
return -1;
return strcmp(u1->name, u2->name);
}
I suppose that in any case the data member name is initialized and contains at least an empty string "".
In this case the comparison function can look like
int compareDataT( const void *v1, const void *v2 )
{
const Data_t *u1 = v1;
const Data_t *u2 = v2;
return *u1->name && *u2->name ? strcmp( u1->name, u2->name )
: !*u1->name - !*u2->name;
}
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEXT_LEN 10
struct StructA{
char name[TEXT_LEN];
int year;
};
typedef struct StructA Data_t;
int compareDataT( const void *v1, const void *v2 )
{
const Data_t *u1 = v1;
const Data_t *u2 = v2;
return *u1->name && *u2->name ? strcmp( u1->name, u2->name )
: !*u1->name - !*u2->name;
}
int main(void)
{
Data_t data[] =
{
{ "", 2020 }, { "A", 2020 }, { "", 2020 },
{ "B", 2020 }, { "", 2020 }, { "C", 2020 }
};
const size_t N = sizeof( data ) / sizeof( *data );
qsort( data, N, sizeof( Data_t ), compareDataT );
for ( size_t i = 0; i < N; i++ )
{
printf( "{ \"%s\", %d } ", data[i].name, data[i].year );
}
putchar( '\n' );
return 0;
}
Its output is
{ "A", 2020 } { "B", 2020 } { "C", 2020 } { "", 2020 } { "", 2020 } { "", 2020 }

How can I pass a generic struct to a function in C?

I'm beginner in C programming and I have a doubt about to pass a generic struct to a function in C.
Here is what I have:
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
And I want to do something like this:
void changeName(struct *s, newName[20]) {
strcpy(s->name, newName);
}
If someone has already asked that, please disconsider this and sends me the issue link.
Someone can help me?
Thanks.
Using a union
One approach would be to add a structure containing a union, itself containing pointers to product and category structures, as well as an enum to identify the type of data in the struct. This union, or a pointer to it, could be passed to a change_name() function.
Here is an example that would work in C11. It uses an unnamed union member, so this is not valid C99 code:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
};
} generic;
void change_name(generic *gen, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
generic gen_prod_a = { .type = PRODUCT, .prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .cat = &cat_a };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&gen_prod_a, "gadget");
change_name(&gen_cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
This could be made to work in C99 by naming the union:
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
product *prod;
category *cat;
} data; // named for C99
} generic;
/* ... */
generic gen_prod_a = { .type = PRODUCT, .data.prod = &prod_a };
generic gen_cat_a = { .type = CATEGORY, .data.cat = &cat_a };
/* ... */
void change_name(generic *gen, const char *new_name)
{
switch (gen->type) {
case PRODUCT:
strcpy(gen->data.prod->name, new_name);
break;
case CATEGORY:
strcpy(gen->data.cat->name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
Alternatively, one struct type could hold an enum identifier and a union containing the product and category structures. This approach may seem a bit more streamlined:
#include <stdio.h>
#include <string.h>
typedef struct {
enum { PRODUCT, CATEGORY } type;
union {
struct {
char name[20];
float price;
} prod;
struct {
char name[20];
int type;
} cat;
} data;
} record;
void change_name(record *rec, const char *new_name);
int main(void)
{
record prod_a = { .type = PRODUCT };
change_name(&prod_a, "widget");
prod_a.data.prod.price = 1.99;
record cat_a = { .type = CATEGORY };
change_name(&cat_a, "general");
cat_a.data.cat.type = 1;
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.data.prod.name);
printf("cat_a.name = %s\n", cat_a.data.cat.name);
return 0;
}
void change_name(record *rec, const char *new_name)
{
switch (rec->type) {
case PRODUCT:
strcpy(rec->data.prod.name, new_name);
break;
case CATEGORY:
strcpy(rec->data.cat.name, new_name);
break;
default:
fprintf(stderr, "Unknown type in change_name()\n");
}
}
Using a type-generic macro
Both of the above approaches are a little bit awkward. Another solution, available for C11 only, is to use the _Generic keyword in a type-generic macro. Here, functions are written for each expected data type, and a macro selects which function definition is to be used based on type. A virtue of this approach is that as new types are added, only new functions and updates to the type-generic macro are needed to handle them.
#include <stdio.h>
#include <string.h>
#define change_name(S, N) _Generic ((S), \
prod_ptr: change_name_prod, \
cat_ptr: change_name_cat \
)((S), (N))
typedef struct {
char name[20];
float price;
} product;
typedef struct {
char name[20];
int type;
} category;
typedef product *prod_ptr;
typedef category *cat_ptr;
void change_name_prod(product *prod, const char *new_name);
void change_name_cat(category *cat, const char *new_name);
int main(void)
{
product prod_a = { .name = "widget", .price = 1.99 };
category cat_a = { .name = "general", .type = 1 };
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
change_name(&prod_a, "gadget");
change_name(&cat_a, "specific");
printf("prod_a.name = %s\n", prod_a.name);
printf("cat_a.name = %s\n", cat_a.name);
return 0;
}
void change_name_prod(product *prod, const char *new_name)
{
strcpy(prod->name, new_name);
}
void change_name_cat(category *cat, const char *new_name)
{
strcpy(cat->name, new_name);
}
All of the above programs have the same output:
prod_a.name = widget
cat_a.name = general
prod_a.name = gadget
cat_a.name = specific
You have already typedef-ed the structures. You can use these other names.
For example, if the name is product, first create a variable and call the function
product var={"name", 1.2};
changeName(&var, "AnotherName");
Then pass this variable to a function
void changeName(product *s, char newName[])
{
strcpy(s->name, newName);
}
Generic programming, which implies type-safety just doesn't really exist in C. But there are ways around that.
What I understand from your question, is 'Can I define a function that can be applied to common elements of different structures?
Let's expand you example a bit, to have items which share a common trait.
struct info
{
char name[20];
int id;
};
struct product
{
Info info;
int price;
};
struct category
{
Info info;
int type;
};
You can now define a function that would work safely on the traits shared by both product and category.
void changeName(info* p, const char* name)
{
strcpy_s(info->name, sizeof(info->name), name);
}
int main()
{
category cat;
product prod;
memset(&cat, 0, sizeof(cat));
memset(&prod, 0, sizeof(prod));
changeName(&cat.info, "Category 1");
changeName(&prod.info, "blue product");
return 0;
}

Initialize sized, static string lists in C

I want to create string lists with a discoverable size and am not sure if I have the right method/syntax. Here is my attempt:
typedef struct {
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Is this the right approach? Note that I do not want to hardcode the size into the structure because I want to use the same type to define many different lists. For example, imagine the following function:
void printList( STRLIST* pList ){
for( int x = 0; x < pList->size; x++ ) printf( "%s\n", pList->list );
}
It can be done with C99 compound-literals and a slight change:
http://coliru.stacked-crooked.com/a/4497d2645ad21b74
typedef struct STRLIST{
unsigned int size;
char** list;
} STRLIST;
static STRLIST listMediaType = {
.size = 7,
.list = (char*[]){
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
},
};
Alternative for C90 (thus without compound-literals and designated initializers): http://coliru.stacked-crooked.com/a/5cc95d25afc18c91
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
};
static STRLIST listMediaType = {
sizeof list / sizeof *list,
// Used sizeof to avoid manually typing the lists length
list,
};
As an aside, an array with a sentinel-NULL is far simpler than a counted array.
Does not even need a new type.
static char* list[] = {
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal",
0
};
void printList(char** pList){
while(*pList) printf( "%s\n", *pList++);
}
You may check this code:
#include <stdio.h>
typedef struct {
unsigned int size;
char* list[];
} STRLIST;
static STRLIST listMediaType = {
7,
{
"Book",
"Map",
"Booklet",
"Pamphlet",
"Magazine",
"Report",
"Journal"
}
};
int main() {
printf("struct size: %d\n", listMediaType.size);
int i;
for (i = 0; i < listMediaType.size; i++)
printf("struct elem[%d] = \"%s\"\n",
i,
listMediaType.list[i]);
return 0;
}
I think there are 2 problems in your approach:
Is TYPEDEF syntactic correct in C? I think you should write it in lowercase.
If you want to initialize a struct, just use the brace and without .attributes
Hope this one will help.
Thanks

initializing a structure array in c with #define

The following code gives me this warning:
tag_info.h:17: warning: missing braces around initializer
tag_info.h:17: warning: (near initialization for âtag_list_data[0].subtagsâ)
I have tried alot of things but nothing seems to be working. Can anyone please suggest something
typedef struct Attr{
char attr_name[64];
value_type_t value;
int mandatory;
}Attr_t;
typedef struct Tags {
unsigned int tag_id;
Attr_t *attr_list;
char *tag_name;
int tag_type;
int subtags[html_subtag_num];
}Tags_t;
Tags_t tag_list_data[150] = {
#include "tag_info.h"
{0,0,0,0,0}
};
where the "tag_info.h" contains :
#if defined(TAG_DEFINE)
#undef TAG_DEFINE
#else
#define TAG_DEFINE(a,b,c,...) {.tag_id=a, .tag_name=#b, .tag_type=c, ##__VA_ARGS__}
#endif
TAG_DEFINE(0,TAG_NONE,0,0),
TAG_DEFINE(1,!--,0,0),
TAG_DEFINE(2,!doctype,0,0),
TAG_DEFINE(3,a, 1, 1, 117, 59,11,118,92,100),
You are initializing subtags as if it were multiple members of the Tags struct:
typedef struct Tags {
...
int subtags_0;
int subtags_1;
int subtags_2;
} Tags_t;
Tags_t t = { ..., 0, 1, 2 };
But it is an array. Thus you should initialize it as a single entity.
typedef struct Tags {
...
int subtags[html_subtag_num];
} Tags_t;
Tags_t t = { .tag_id = 0, ..., { 0, 1, 2 } };
// or
Tags_t t = { .tag_id = 0, ..., .subtags = { 0, 1, 2 } };
Also, you don't need to use concatenation (##)
#define TAG_DEFINE(a,b,c,...) { ..., ## __VA_ARGS__}
In the end, it should look like
#define TAG_DEFINE(a,b,c,...) { ..., .subtags = { __VA_ARGS__ } }
...
Tags_t tag_list_data[150] = {
...
{ 0,0,0,0,{0}}
}
instead of
#define TAG_DEFINE(a,b,c,...) { ..., ##__VA_ARGS__}
...
Tags_t tag_list_data[150] = {
...
{ 0,0,0,0,0 }
}

Resources