Comparing Char* to Enum variable in C - c

So I'm trying to utilize Enumerated types in C for the first time. So I have an Enumerated "variable?" declared and I also have a struct which has a variable of the Enumerated type(among other things). Finally I have a static array for which there is an element containing each of the enum "types?" in the same order they were declared. I am hoping to use the enum type to act as an index for the array.
So my problem is that I need to somehow relate a char* variable to the enumerated type. If I KNOW that the Char* variable is one of the enum types, is there some way to assert that without having to look at each char to determine which specific enum"option" it is?
Example:
enum example = {abc,def}
struct _strExample {
enum example letters;
....
};
typedef struct _strExample strEx;
static strEx Table[2] = {
{abc,...}
{def,...}
};
//Given char* "abc" , want either example.abc or 0 ( correct index of table)
So given the char* "abc"(does not need to be char*), is there a simple way to get either the correct enum "type?"(abc or def)or the correct index of the table? I know that I could check all the individual chars in the char* and manually determine which enumerated "type?" it is, but I am going to be working with a very large set of enumerated variables and this kind of thing is exactly what I was trying to avoid. any help or advice you guys could give on enumerated types and/or my design would be most appreciated.

Use a an array of strings where the index into the array is the enum value. If the strings are all short, or all about the same length, storing the string in the array makes sense. Otherwise, use a char* pointer.
typedef enum enum_t { plugh, plover, xyzzy, y0 } enum_t;
const char *etable = { "plugh", "plover", "xyxxy", "y0", NULL };
With that, you can convert with a simple search like:
enum_t find_enum(char *sval)
{
enum_t result=plugh; /* value corresponding to etable[0] */
int i=0;
for (i=0; etable[i]!=NULL; ++i, ++result)
if (0==strcmp(sval, etable[i])) return result;
return -1;
}
The enum-to-string converstion is simply etable[e-plugh]. Those allow for a different definition of enum_t where the first meaningful value may not be 0, but the values are sequentially assigned thereafter.

No, you can't lookup any scalar value from a character array. You have to iterate over a set of strings to compare and find the relation to the enum member.
You can use an array of structs
typedef struct { int value; const char * name; } lookup_t;
lookup_t lookup[] = {
{ 1, "One"},
{ 0, NULL} // end tag, alternatively use the _countof(lookup) to get the number of elements
};
and compare your char* with the name member. Then you use the value on match.

Use if :
char *ex = "abc";
strEx strex;
if(!(strcmp("abc",ex))) {
strex.letters = abc;
}
else {
strex.letters = def;
}

Related

What is the purpose of an array with undefined length but only one int element?

I have a headerfile which declares these arrays:
int stVal_On[] = {2};
int stVal_Off[] ={1};
int subVal_On[]={1};
int subMss[]={1};
int subVal_Off[]={0};
The dereferenced arrays are then used in structs that are declared:
Definition of WriteData struct:
/* Write structure used in loop for Read- and Write Tests */
typedef struct WriteData {
char* name; // MMS object name
const VOID* data; // Data to write
const SINT32 localFormat; // SVI type (on server)
const SINT32 dataLength; // length of data to write/read
const SINT32 NbrofElmnts; // Number of elements to write/read
char* description; // SVI type as String (on server)
char* SVI_Name; // SVI address of the SVI mapped on server
UINT32 svi_Length; // length of SVI variable on server (used for readback)
} WriteData;
What is the purpose of this int arr[] = {1}; idiom? Why use arrays at all if only one value is assigned?
Well, one reason I can think of has to do with code organization. If you write your code in a tabular form:
struct {
char const *file_name;
uint16_t flags;
// Other data
} table [] = {
{ .file_name = "/usr/bin/foo", .flags = 0x0 },
};
for (size_t i = 0; i < sizeof(table)/sizeof(table[0]); ++i) {
// do something meaningful with a table row table[i]
}
While it's just an array of 1 now, if you need to add more cases, your code is already written well for it. You'd just need to add another "row' to the table initializer.
All the definitions create arrays with only one element, true. The actual use case may vary.
One commonly used scenario is, this variable can be passed as a function argument and it will be possible to change the content of the array (the only element value) from the called function, which in case of a non-array variable is not possible. This maybe not the very smart way, but still, it's possible and someone chose to use it.
Also, as always, array size determined by the supplied initializer leaves the room for expansion without requiring major code changes.

sizeof of string literal inside a struct - C

I have the following code:
struct stest
{
int x;
unsigned char data[];
} x =
{
1, {"\x10\x20\x30\x00\x10"}
};
int main()
{
printf( "x.data: %d\n", (int)x.data[0] );
return 0;
}
Which works fine. However, I need to use the size of the "data".
If I do:
printf( "sizeof x.data: %d\n", (int)sizeof(x.data) );
I get the error:
invalid application of ‘sizeof’ to incomplete type ‘char[]’
Is there a way to get the size of "data" in this situation, or maybe a suggestion of an alternative method I could use?
The compiler I am using is gcc 4.6.3.
Since x.data is a null terminated char array you could just use strlen function.
printf( "sizeof x.data: %u\n", strlen(x.data)+1 );
This code will not work correctly if the array contains null. In this case you need to store length of the array in separate member of struct.
As others have said, strlen will get you what you want.
The reason you're running into trouble isn't due to the string literal aspect, but rather the lack of a definite size of the array in your struct. It's an incomplete type. The compiler doesn't know how big the array is, and so sizeof can't figure it out.
Specifically, this is a "flexible array member". C99 added these. Structs with array's with an incomplete array as the last element (so it has room to grow).
Sizeof gets the size of the datatype.
Sizeof when applied to arrays, gets the size of the whole array.
Sizeof when applied to structs with a flexible array member, ignores the array.
Sizeof when applied to incomplete types simply fails. It gives up trying to figure out how big the array is.
So long story short, slap a number in your array. (Or pass along that information)
struct
{
int x;
int thesizeofmyarrayisfive = 5;
unsigned char data[5];
}
Add a size field to the structure.
#define DATA ("\x10\x20\x30\x00\x10")
struct stest
{
int x;
size_t size;
unsigned char data[];
} x =
{
1, sizeof DATA, { DATA }
};
There's only two options:
Store a terminating byte. Often people use the null character for this. Of course, you must make sure that the terminating byte is not found in the valid data part of the array.
Add a length member to your struct.

How to implement an enum with specific values for its members?

I could be going about this all wrong, and it could be that an enum does is not a good way to solve this problem, but I am really not sure where to go with it otherwise.
Basically, I have non-sequential codes that correspond to certain strings. For example,
9 = "Enter"
10 = "Right"
15 = "Left"
17 = "Down"
And so on. I currently have this implemented with a large set of definitions:
#define ENTER_INDEX 0
#define RIGHT_INDEX 1
That is used to index into a char* array:
char* array[] = { "Enter", "Right" };
And when I receive information regarding which code was received, I then print the strings with a huge switch-case.
Any ideas on how to do this more efficiently? Is an enum a good approach?
Sure, you can use an enum, but that won't help you associate the names with the numerical values.
The problem is that you can't declare an enum and a string "in parallel" from the same source code characters, without using trickery such as X macros. Even then you probably won't solve the requirement for different casing which your code shows. Which you might want to avoid, because obfuscation.
The enum would be just:
typedef enum {
ID_ENTER = 9,
ID_RIGHT = 10,
ID_LEFT = 15,
ID_DOWN = 17
} Id;
I would then use C99's fantastic support for explicit indexes in array initializers to declare an array of strings indexed by an Id:
static const char *id_names[] = {
[ID_ENTER] = "Enter",
[ID_RIGHT] = "Right",
/* add more */
};
Note that the above is independent of the order, since each element initializer has an explicit index. This makes it very robust.
You can of course use a macro to cut down on the repetition, but that will make an all-caps string array:
#define DECL_ID(i) [ID_ ## i] = #i
static const char *id_names2[] = {
DECL_ID(ENTER), DECL_ID(RIGHT), /* add more */
};
To implement an enum with specific values for its members can be done by
enum options_en
{
Enter=9,
Right=10,
Left=15,
Down=17,
Default=0;
} ;
then you can declare a variable which can take only values defined in the enumerated type
options_en opt_val = Default;
For exploring more information about your question , refer this link, Found it very useful and is relevent to your question
http://www.cprogramming.com/tutorial/enum.html
A dictionary or hash table can be used. In c++ stl libraries I don't recall the name of the collection but in short y. use dictionaries/hashtables with generics.
So in your case you fill up the dictionary with key value pairs and when your later use the collection you can get a value using your key.
So it gets rid of switch statements and enums and will allow you to map any two types. Here is pseudo code
Value = dictionary[key]
So if key is 0 then the value will be set to Enter based on your example.
In short lookup examples for c++ and dictionary as I am answering from mobile phone and could not direct you to the exact collection name.
You can also create a map during initialization:
#include<stdio.h>
typedef struct { int code; const char *str; } key_info;
key_info keys[] = {
{9, "Enter"}, {10, "Right"}, {15, "Left"}, {-1, NULL}
};
#define MAX_KEY_CODE 15
size_t keymap[MAX_KEY_CODE + 1];
int main ( ) {
size_t i;
for (i = 0; keys[i].str; i++) {
keymap[keys[i].code] = i;
}
printf("%s\n", keys[keymap[10]].str);
return 0;
}
A huge switch is not a bad solution. The question is why do you need an extra array of names. Why don't you return directly string literals from the switch?
char *name(int code) {
switch (code) {
case 9: return("Enter");
case 10: return("Right");
case 15: return("Left");
...
}
}

2D array using strings

I'm stuck on some homework which isn't graded (its meant for practice).
I have to create a function called find_name that takes 2 arguments. The first argument is a 2D array of names (strings), and the second is a character string which is used to find the name in the 2D array, the function must return 1 if found else 0.
When i call the function (which is empty right now), I get this warning: passing argument 1 of 'find_name' from incompatible pointer type
Here is the important bits.
In Main
char strNameList[][2] = { { "Luca","Daniel"} ,{"Vivan","Desmond"},{"Abdul","Justin"}, {"Nina","Marlene"},{"Donny","Kathlene"} };
char strFindName[] = "\0";
printf("Please enter a name to look for: ");
gets(strFindName);
nSearch = find_name(strNameList, strFindName);
The Function
int find_name(char strNameList[][2], char strLookUp[])
I'm new to C (I'm a student), and I'm completely confused about strings (string arrays etc).
I'm assuming you want a 2D array of char pointers. Your declaration of strNameList is incorrect in both locations in your program. You have:
char strNameList[][2] = { { "Luca","Daniel"} ,{"Vivan","Desmond"},{"Abdul","Justin"}, {"Nina","Marlene"},{"Donny","Kathlene"} };
But char[][N] is declaring a 2D array of chars, not char* Therefore you're being warned by the compiler you're assigning a raft of pointer values to items of type char
Change both your declarations (your variable and your function parameter) to:
const char *strNameList[][2]
which declares an array of unknown length of arrays of two char*, which now matches your initialization lists. Also, the const is added because (a) I'm assuming you are not planning on modify that name list in your function, and (b) writable string literal declarations assigned to char* via initializer is undefined behavior in C, and officially deprecated in C++, so you should not be using it regardless. Likewise, your lookup-name is probably not being modified either, so also declare it const.
Result:
const char * strNameList[][2] = {
{"Luca","Daniel"} ,
{"Vivan","Desmond"},
{"Abdul","Justin"},
{"Nina","Marlene"},
{"Donny","Kathlene"}
};
and in your function:
int find_name(const char * strNameList[][2], const char strLookUp[])
Last but certainly not least, unless you have a crystal ball your find_name() function has no way of knowing with the given information how many names are in the name list being passed. I'd rather you see this now rather than wonder what happened later. you need to either (a) terminate the list with a token-value that find_name() knows about, or (b) pass the number of names in the list to find_name(). To each their own, but I prefer the latter of these:
int find_name(const char * strNameList[][2], size_t nNameListSize, const char strLookUp[])
and invoke it on your caller side by:
find_name(strNameList, sizeof(strNameList)/sizeof(strNameList[0]), strFindName)
Do it this way:
#define STOPPER_NAMELIST NULL
char * strNameList[][2] = {
{ "Luca","Daniel"},
{"Vivan","Desmond"},
{"Abdul","Justin"},
{"Nina","Marlene"},
{"Donny","Kathlene"}
{STOPPER_NAMELIST, STOPPER_NAMELIST}
};
size_t sizeNameList(const char * strNameList[][2])
{
size_t size = 0;
while ((strNameList[size][0] != STOPPER_NAMELIST) &&
(strNameList[size][0] != STOPPER_NAMELIST))
++ size;
return size;
}
int find_name(char * strNameList[][2], char strLookUp[])
{
size_t size = sizeNameList(strNameList);
...
}
...
nSearch = find_name(strNameList, strFindName);
This approach uses an open array ([]) of char * arrays with 2 entries.
Update:
You could add a stopper element to the array carring the names, then there is no need to pass around the array's size along with array itself, as the size could alway be determined by scanning the array members until the stopper is found.
Your function find_name() is looking for a 2-D array of characters ie:
char arr[][2] = { { 'a', 'b'}, ...
if you want to make them strings you need:
char *arr[][2] = { {"John", "Smith"}, ...
Then in the function parameter list you need:
void find_name(char *something[][2])
{
printf("first name: %s, second name: %s\n", something[0][0], something[0][1]);
And in your main() function call it just by:
find_name(arr);

parsing a .conf file in c

Perhaps this bridge likely has been crossed many times and in many ways... reading a simple text .conf file and acting upon its entries.
In my case, the file format is simple.. a series of tokens and assignments, as in:
token_name_1 value
with a tab character as the field delimiter and a unix line-ending for each the record.
The .conf file directly alters certain program configurations, all of them stored in a single structure. Variables of types Integer, float, char[], and *char are represented in the structure.
A quick but boring approach involves, for example:
if (strcasecmp(token,"token_name_1")==0)
token_name_1=value;
But I determined that it would be sweet to do the deed in a nice tight loop. In C.
So it seemed best to construct an array which provides pointers to each of the structure variables I wish to expose; another that provides the name of the variable; and a third which describes the stored data type and a desired default value.
These look like this:
const char* allowed_tokens[] =
{
"loglevel",
"debugecho",
"errorSqlDisable",
"ClearErrorDbOnExit",
"\0" // terminates list
}
int *varpointers[] =
{
&appinfo.nLogLevel,
&appinfo.debugEcho,
&appinfo.OWFSLogLevel,
&appinfo.OWFSLogEchoToDisplay,
0 // terminates list
};
char *varDatatypes_defaults[] =
{
"I|6", // for LOG_INFO
"B|false",
"I|0",
"B|true",
"\0" // terminates list
};
The loop looks like this (pseudocode):
row=0;
while (read a line of the .conf file into cLine)
{
get the token_name and value from cLine
check if allowed_tokens[row]==0 and if true, exit the loop
// example cLine= "debugecho false"
find match to "debugecho" in allowed_tokens. This provides an offset into varpointers and varDatatypes.
get the default data type and default value tokens from varDattypes_defaults[row]
Do the assignment. For example, if the data type=="I":
*varpointers[row]=atoi(value);
++row;
}
This technique works fine, but there are two problems.
It would be preferable to combine the three arrays into a single array. Is there a best practice here?
The array of pointers (varpointers[]) is defined as *int. I did so as I want it to hold pointers. However if the variable pointed to is not an integer data type, warning: initialization from incompatible pointer type is triggered. Of course, char * and int * cannot be mixed... so how otherwise could this be done such that a single pointer array is used?
I realize I can do all this in c++. This luxury is not an option at this point.
You can combine them into one array by structs, e.g.
typedef struct { char *token; void *var; char *defaults; } the_type;
the_type the_data[] = { { "loglevel", (void*)&appinfo.nLogLevel, "I|6" },
{ "debugecho", (void*)&appinfo.debugEcho, "B|false" },
...
};
The generic pointer type is void *. Your code has to ensure you use the correct type when actually writing to the variable being pointed to, e.g. *(int*)the_data[0] = 42;.
I would use an enumeration to specify the types so you don't have to parse a string. The values could be stored in an union.
typedef enum {
BOOLEAN,
INTEGER,
} type_t;
typedef union value {
bool boolean;
int integer;
} value_t;
typedef struct token {
char *name;
type_t type;
value_t value;
} token_t;
Now you can define your defaults like so:
token_t data[] = {
{ "loglevel", INTEGER, { 6 } },
{ "debugecho", BOOLEAN, { false } },
{ "errorSqlDisable", INTEGER, { 0 } },
{ "ClearErrorDbOnExit", BOOLEAN, { true } },
{ 0 }
};
This will get pretty cumbersome if the number of configuration keys gets large. You might want to think about storing the configuration in a hash table or a tree.
Here is a short example that seems to accomplish what you want.
If we are talking about the same data type, use double pointers (you get an array of arrays)
Declare a struct holding your pointers, then use a pointer to your struct to work on.
For declaring a general pointer, you can use void instead of int. But then every time you have to cast the pointer to use it properly.

Resources