Implementing a menu like device without conditionals for each command - c

Suppose I'm trying to implement a "menu" of sorts that asks the user to enter a command and then calls the function that executes that command. Instead of having a block of conditionals for each command, I decided to declare an array of strings that contains each command name and then compares the user's input with the strings in that array to see what to do next.
Something like:
char* commands[] = {"cmd", "cmd1", "cmd2"};
Then:
while(strcmp(cmd, "end") != MATCH) {
printf("?:");
scanf("%s", cmd);
for(i = 0; i < CMD_NUMBER; i++) {
if(strcmp(cmd, commands[i]) == MATCH) {
/*do something */
}
}
}
Is there a way to call the function without having any conditionals or switch statements at this point? I was thinking of implementing a struct of function pointers, with a member for each command, and then using that, but I'm not exactly sure how or if that's even possible.

Create a struct that contains both the command and a pointer to the function:
typedef struct {
char * cmd;
void (* func)();
} Command_t;
Command_t commands[] = {
"cmd", func_cmd,
"cmd2", func_cmd2
};
Note: You need to declare the functions above this structure, else your compiler will balk at them.
(Edit) Just for completeness, you'd use this structure as
for(i = 0; i < sizeof(commands)/sizeof(commands[0]); i++)
{
if(!strcmp(cmd, commands[i].cmd))
{
commands[i].func();
break;
}
}

Related

Run a function and check if another function is already executed using C

Using C, I want to run one function based on another. I need to check if a specific function is executed. if yes, then I want this function to execute as well when called, otherwise not.
I am reading some text from a file. in the first function, I want to read them and print them. now in the second function, I need a condition, that if the first function is executed, then run this as well. otherwise, do nothing.
How can I do that?
EDIT
NOTE: THIS IS THE COMPLETE SOLUTION. AFTER THE QUESTION WAS ANSWERED.
My code is here:
#include <stdio.h>
static int already_run = 0;
void Reading_Function(FILE **rf)
{
already_run = 1;
*rf=fopen("file.txt","r");
if(rf==NULL)
{
printf("Error in file openning.");
return 0;
}
char first [120];
fscanf(*rf,"%s",first);
printf("Value: %s", first);
}
// this is the second function
void Second_Function(FILE *rf)
{
if (already_run)
{
char second [50];
fscanf(rf,"%s",second);
printf("Value: %s", second);
}
else
return;
}
int main()
{
char t;
FILE *rf;
while(scanf("%c", &t)==1)
{
switch(t)
{
case 'f' :
Reading_Function(&rf);
break;
case 's' :
Second_Function(rf);
break;
}
}
return 0;
}
Let me know if the question is not clear. Thanks.
The comments above already answer your question. Just to keep things simple, here is what the code would look like:
static int already_run = 0;
void Reading_Function(FILE *rf) {
already_run = 1;
// ...
}
void Second_Function(FILE *rf) {
if (already_run) {
// ...
} else {
// ...
}
}
That said, if what you're trying to do is only have people call Second_Function but have the stuff in First_Function run the first time Second_Function is called, a better way to do this is:
void Second_Function(FILE *rf) {
static int already_run = 0;
if (!already_run) {
already_run = 1;
// Initialization code goes here. You can even split it out
// into a second function if you want, in which case you would
// just invoke that function here.
}
// ...
}
That way you don't have any global variables to worry about.
Of course, both methods break down if your code is multi-threaded; in that case, you should use a once (like pthread_once_t, call_once, InitOnceExecuteOnce, or something which abstracts the different APIs away for portability).

C - should I use a variable array of function pointers

This question is about how to solve my problem on the level of how I design my program. For a school project, I'm building a shell, which has several built-in functions. One of these function's purpose (cmd_type) is to check to see if the argument provided is in that list of functions. Here is a partial implementation of it:
int cmd_type(int argc, char *argv[]) {
if (argc == 2) {
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmds_name[i], argv[1]) == 0) {
printf("%s is a shell builtin\n", argv[1]);
return 0; // found it
}
}
// still need to search path, call stat(path/cmd)
errmsg("not implemented! type", 1);
} else {
err_msg("type", 1);
}
}
Defining manual if statements for every function my shell supports sounds like a bad choice because the list might expand over time, and I need to store the list of function names anyway. So originally, I planned to define an array of function names and an array of their pointers, like so:
char cmds_name[BUILTIN_FUNC_COUNT-1][16];
char (*cmds_ptr)(int,*char[])[BUILTIN_FUNC_COUNT-1];
// make list of built-in funcs
strcpy(cmds_name[0], "exit");
strcpy(cmds_name[1], "cd");
// make list of func pointers
cmds_ptr[0] = &cmd_exit;
cmds_ptr[1] = &cmd_cd;
They're accessed like so:
// try builtin cmds
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmds_name[i], argv[0]) == 0) {
last_cmd_err = (*cmds_ptr[i])(argc, argv);
continue; // we found it, so next loop
}
}
Then they'd each happily take (int argc, char *argv[]) as arguments. But the cmd_path() needs access to the list in addition to those arguments, so I'd have to define it as a global, or define a global pointer to it... In the process of researching this, I found this answer, saying a similar approach was really bad style: https://stackoverflow.com/a/41425477/5537652
So my questions are: Is this a good way to solve this problem, or should I just do if/else statements/is there a better way? Would you recommend a global pointer to the array of function names?
I am going to propose a structure of cmd_name and function pointer like this:
typedef struct{
char cmds_name[16];
char (*cmds_ptr)(int,*char[]);
} cmd_type;
Now define a static table of this type for all your cmds:
static const cmd_type cmd_table[] = {
{"exit", &cmd_exit},
{"cd", &cmd_cd},
.......
.......
};
Finally access it like this:
for (int i = 0; i < BUILTIN_FUNC_COUNT; i++) {
if (strcmp(cmd_table[i].cmds_name, argv[0]) == 0) {
last_cmd_err = (*cmd_table[i].cmds_ptr)(argc, argv);
continue; // we found it, so next loop
}
}
The decision to choose between if-else vs a global table is a matter of personal taste and coding style. I would prefer the above solution simply because it improves ** code readability** and reduces clutter. There may be other constraints in your environment that can influence your decision - like if the no of table entries is huge and there is a limitation on global memory space - the if-else route would be a better choice..
HTH!
I would not go with if-else statements. There is nothing wrong with solution (2) proposed in https://stackoverflow.com/a/41425477/5537652.
You could have a table with a string and a function to service an entry:
typedef struct cmd_desc
{
char cmd[80];
int builtin_cmd(int argc, char **argv, void *extra);
} CMD_DESC;
static CMD_DESC descTable[] =
{
{ "exit", cmd_exit },
{ "cd", cmd_cd },
{ "$ON_OPEN_CMD", OnOpenCmd },
{ "$OPEN_EXTRA_CMD", OpenExtraCmd },
{ "$AC", ActionCmd },
{ "$AD", ActionDataCmd },
{ "$EC", ExtraCmd },
{ "$TC", TextCmd },
{ "", NULL }
};
int cmd_exit (int argc, char **argv, void *extra)
{
//...
}
Access/execution:
for (int tokenIndex=0; strcmp(descTable[tokenIndex].cmd,""); tokenIndex++) //search table
{
if ( strcmp( (descTable[tokenIndex]).cmd, argv[0] ) == 0 )
{
int ret = (*(descTable[tokenIndex]).builtin_cmd( argc, argv, extra);
}
}
I used the above approach in a my applications and it worked well for me.
The table can be easily expanded and the readability of the table is better than if/else chain.

Array of function pointer

Is it possible to replace all of these "if, else if ..." with an array of function pointers in this example of code ?
if (strncmp(buff, "ls\n", 3) == 0)
my_ls();
else if (strncmp(buff, "cd\n", 3) == 0)
my_cd();
else if (strncmp(buff, "user\n", 5) == 0)
my_user();
else if (strncmp(buff, "pwd\n", 4) == 0)
my_pwd();
else if (strncmp(buff, "quit\n", 5) == 0)
my_quit();
I'm trying to get something like this :
void (*tab[5]) (void);
tab[0] = &my_ls;
tab[1] = &my_cd;
tab[2] = &my_user;
tab[3] = &my_pwd;
tab[4] = &my_quit;
I created a code to illustrate what you wanted to do, because I it's pretty entertaining.
#include <stdio.h>
#include <string.h>
// your functions
void my_ls() { puts("fun:my_ls") ;}
void my_cd() { puts("fun:my_cd") ;}
void my_user(){ puts("fun:my_user");}
void my_pwd() { puts("fun:my_pwd") ;}
void my_quit(){ puts("fun:my_quit");}
int main(int argc, char const *argv[])
{
char* buff="ls\n"; // the string you have to compare
void (*tab[5]) (void)={my_ls,my_cd,my_user,my_pwd,my_quit};
char *names[5]={"ls\n","cd\n","user\n","pwd\n","quit\n"};
int i;
for (i=0; i<5; i++)
{
if(strncmp(buff,names[i],strlen(names[i]) )==0){
tab[i]();
return 0;
}
}
return 0;
}
There are other ways to write it. Actually my_function is the same as &my_function since a function name alone is converted to the adress of the function.
Also tab[i]() is equivalent to (*tab[i])()... Those are weird behaviours but I think it's specified by C standard
There's no problem with an array of function pointers, but you'd need to convert the sequence of boolean strncmp() results to a single index.
If the list is long, the hash table idea might be a winner. For compact, simple code and easy maintenance, I've used an array of structs:
typedef struct cmdtable_t
{
void (*fptr)();
unsigned char length
char name[11];
} cmdtable_t, *pcmdtable_t;
cmd_table_t commands = {
{ my_ls, 2, "ls"},
{ my_cd, 2, "cd" },
{ my_user, 4, "user" },
...etc.
};
That could also be what a hash table entry looks like, could be sorted in advance to allow a binary search, or simply sequentially searched for a KISS version until you find out whether this needs optimizing at all.
I think you want a dictionary or hashtable:
Use buff as string key
Use function pointer as values

User entered string run a particular function in c

Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !

strcmp string and character array in c

Here is the code I have. I'm trying to do a string comparison. A serial input reads what keys are pressed and sets cmd.command to what was typed on the keyboard. Then I take that and do a string comparison to see if it is a command that's within my list. What I'm stuck on is the string comparison.
typedef struct {
const char *cmd;
void (*cmdFuncPtr)(void);
}CmdStruct;
typedef struct {
char command[16];
char argument[16];
} Command;
Command cmd;
CmdStruct cmdStructArray[] = { {"led", LEDHandler },
{"relay", RelayFunction }, };
void ProcessCommand() {
for (j = 0; j < sizeof(cmdStructArray)/sizeof(cmdStructArray[0]); j++) {
if(strcmp(cmdStructArray[j].cmd, cmd.command) == 0) {
// do stuff
}
}
}
If I type in "led", then these two printf statements print the same thing.
printf(cmdStructArray[0].cmd);
printf("%s", cmd.command);
How can I get the string comparison to work?
Your cmd.command commands likely have hidden trailing whitespace. Strip the whitespace before running comparisons. (Thanks David Schwartz in the comments!)
I found a fix, and now strcmp works. I changed the struct in the struct array. Now it's
typedef struct {
char cmd[16];
void (*cmdFuncPtr)(void);
}CmdStruct;
I don't know why this works, and don't know what the difference is. The const char *cmd I had before is also a way to create a "string" in C.

Resources