Initializing an array of structs in C then dereference later - c

I'm trying to build a serial command interpreter, so I want to store my commands in an array. I want each command to have a name and a function pointer so that I can compare the command name to what I typed into and then call the function. I'm not that good with C, so please help! Here is what I have so far.
The command array will be an array of structs. Each struct will have a string and a function pointer. There are errors here, but I don't know how to fix them. These are done before main.
typedef struct cmdStruct {
char cmd[16];
void (*cmdFuncPtr)(void);
}CmdStruct;
void (*ledFuncPtr)(void);
void (*cmd2FuncPtr)(void);
// assign pointers to functions
ledFuncPtr = &LedFunction;
cmd2FuncPtr = &Cmd2Function;
//build array of structs
CmdStruct cmdStructArray[] = cmdStructArray = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
Later on, I will go through the struct array to compare it to the received command.
// go through the struct array to do string comparison on each struct's string member
for (int i = 0; i < sizeof(cmdStructArray); i++) {
// string comparison of received command and string of struct
if(strcmp(cmdStructArray[i].cmd, receivedCmd)==0) {
// dereference function pointer
(*cmdStructArray[i].cmdFuncPtr)(void);
}
}
What parts am I doing wrong, and how do I fix them?

sizeof(cmdStructArray) is not in elements, but rather in bytes.
Use sizeof(cmdStructArray)/sizeof(cmdStructArray[0]).

As it has already been noted, your cycle makes wrong number of iterations. sizeof array does give you the number of elements in the array, but rather the number of bytes in the array. You have to calculate sizeof array / sizeof *array to get the number of elements.
Also, your function call syntax is invalid
(*cmdStructArray[i].cmdFuncPtr)(void);
The above will not compile. You cannot specify void as an argument in function call. (void) syntax can only be used in function declarations. If the function accepts no parameters, the call should look as
(*cmdStructArray[i].cmdFuncPtr)();
Also, this will not compile as well
CmdStruct cmdStructArray[] = cmdStructArray = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
Why are you mentioning cmdStructArray in this declaration twice?
Some additional, essentially cosmetic remarks:
Firstly, since your commands are probably going to be string literals known at compile time, you can declare the first member of your struct as a const char * pointer instead of char array
typedef struct cmdStruct {
const char *cmd;
void (*cmdFuncPtr)(void);
} CmdStruct;
The initialization syntax does not change. This will relieve you of the need to worry about the size of the array (16 that you currently have there).
Secondly, it is not clear why you had to declare intermediate pointers to functions ledFuncPtr and cmd2FuncPtr instead of initializing your array directly. What was the purpose of this
void (*ledFuncPtr)(void);
void (*cmd2FuncPtr)(void);
// assign pointers to functions
ledFuncPtr = &LedFunction;
cmd2FuncPtr = &Cmd2Function;
CmdStruct cmdStructArray[] = { {"led", ledFuncPtr },
{"cmd2", cmd2FuncPtr }, };
when you could simply do this
CmdStruct cmdStructArray[] = { {"led", &LedFunction },
{"cmd2", &Cmd2Function }, };
(without introducing ledFuncPtr and cmd2FuncPtr at all)?
Thirdly, you don't have to use * and & operators with function pointers. This will work too
CmdStruct cmdStructArray[] = { {"led", LedFunction },
{"cmd2", Cmd2Function }, };
and
cmdStructArray[i].cmdFuncPtr();
Anyway, this is a purely cosmetic issue, a matter of personal preference.

Related

Problems with pointers allocation when dynamically build a binary tree in C

studying C for few months, I encounter some difficulties with the use of pointers when dynamically building a binary tree:
Given my code below:
typedef struct TNoeud
{
int data;
struct TNoeud *pFilsGauche;
struct TNoeud *pFilsDroit;
} TNoeud;
void insereData(int data, TNoeud **pRacine)
{
TNoeud *noeud=malloc(sizeof(TNoeud));
noeud->data=data;
noeud->pFilsDroit=NULL;
noeud->pFilsGauche=NULL;
while((*pRacine)!=NULL)
{
if(data<(*pRacine)->data)
{
pRacine=&(**pRacine).pFilsGauche;
}
else
{
pRacine=&(**pRacine).pFilsDroit;
}
}
if(pRacine==NULL)
{
*pRacine=noeud;
}
free(noeud);
}
And in the main:
int main(int argc, const char * argv[]) {
TNoeud *pRacine=malloc(sizeof(TNoeud));
pRacine->data=0;
pRacine->pFilsGauche=NULL;
pRacine->pFilsDroit=NULL;
pRacine=&noeudRacine;
insereData(4, &pRacine);
return 0;
}
I read the following topic https://stackoverflow.com/a/28637104/7866010 for the BAD_ACCESS, but in my case, the pointer is not at NULL, as pRacine is assigned at 0.
I read the following topic https://stackoverflow.com/a/15154553/7866010 , but it didn't help.
I also tried the declaration variant
(*pRacine)->data
found in this topic https://stackoverflow.com/a/346739/7866010 without any difference.
So my questions are :
[SOLVED with TNoeud noeud as pointer instead of local variable. I also changed pRacine in the main the same way] Why do the pointer
*pRacine == NULL
when I pass a pointer to an assigned value as parameter of
insereData(4, &pRacine) ?
[SOLVED the same way] Why does the debugger give me random values to pointers
[1] = 0x00007fff5fbff700)
and datas
(int) data = 1606416544)
I didn't willingly assigned ?
[SOLVED: by deleting the if(pRacine==NULL) condition and replacing it by just (*pRacine)=noeud;] Now no more errors, but the result of
insereData(4, &pRacine);
doesn't impact pRacine : it should be
pRacine->pFilsDroit->data==4
but here it remains at NULL. I don't understand why, as it's not a local variable anymore.
Thanks all for your answers!
Some suggestions(not law).
First in order to not confuse yourself about pointers, just work with them as arrays. it really works and won't confuse you.
For instance given pointer int* ptr, for accessing the first element go as ptr[0].
And the problem is here
if(pRacine==NULL)
{
*pRacine=&noeud;
}
as the noeud is not in dynamic memory, it gets halted.
You simply need to define the noeud as a pointer of the struct by malloc. But for memory sake, please keep an eye for free it once it's not needed.

Quick check to see if structure of function pointers is NULL in C99

In C99 is there an easier way of check if a structure of function pointers is NULL, other than checking each individual pointer?
What I currently have is similar to the following:
typedef struct {
void* (*foo)(int a);
int (*bar)(int a, int b);
} funcs;
void *funcs_dll;
funcs_dll = dlopen("my_funcs_dll.so", RTLD_GLOBAL);
if (funcs_dll == NULL) {
THROW_ERROR;
}
funs.foo = dlsym(funcs_dll, "foo");
funcs.bar = dlsym(funcs_dll, "bar");
if (!funcs.foo || !funcs.bar) {
THROW_ERROR;
}
What I am looking to do is reduce the second if check, so that I do not need to check each individual function. Any suggestions would be helpful.
Not directly, no.
You can't use memcmp() to compare to some constant buffer, since there might be padding inside the structure which will have "random" values. If you can make sure that the size of the structure is exactly the sum of the function pointer fields, you can perhaps go that way.
You can also use a proxy, by i.e. declaring an initial uint32_t member that is a bitset representing which function pointer(s) are valid. Then you can check up to 32 (or 64 with uint64_t) proxy bits in parallel.
If you only want to do this once, my suggestion would be a data-driven approach. Define a table of function names to look for, and process that in a loop, exiting as soon as a dlsym() call fails.
Something like:
const struct {
const char *name;
size_t offset;
} functions[] = {
{ "foo", offsetof(funcs, foo) },
{ "bar", offsetof(funcs, bar) },
};
Data-driven code like this is very powerful, and often very fast.
Make wrapper function for dlsym which will set error flag, if return value is NULL.

Issue regarding getting a field from a structure as a array of string pointers and saving them in an instance variable of an array of string pointers

So i have a struct that i define as followed
struct pastCommand
{
int numberOfCommand;
char *command;
char *commandslist[10];
int commandlistLength;
};
Ive written a function that can print a structure in the way i want
void printHistoryElement(struct pastCommand *currentHistory)
{
if(currentHistory==NULL)
{
}
else
{
int myLength=currentHistory->commandlistLength;
int numberCommand=currentHistory->numberOfCommand;
char *myCommand=currentHistory->command;
char *currentList[] = currentHistory->commandslist;
printf("Commands #%d: %s\n",numberCommand, *myCommand);
for(int i=0; i<myLength; i++)
{
printf("arg[%d] :%s\n",i,currentList[i]);
}
printf("\n");
}
}
When i get an issue on this line
char *currentList[] = currentHistory->commandslist;
With the error saying error: array initializer must be an initializer list
Im not sure exactly what the issue is, they are the same type, an array of pointers to strings, however i cant put my finger on the issue. Some insight on this problem would be very helpful. Thank you.
The empty square bracket [] syntax in declarations is for defining arrays with the size defined by the array initializer. In your code, however, you are simply pointing to some existing array, so you could do it with a pointer. Since your array is an array of pointers, you need a pointer to pointer, like this:
char **currentList = currentHistory->commandslist;
The rest of your code remains the same.
Note that although this will work, it is entirely unnecessary to store a pointer to the array in a local variable. You can rewrite your code without the local, like this:
for(int i=0; i<myLength; i++)
{
printf("arg[%d] :%s\n", i, currentHistory->commandslist[i]);
}

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