2

I just can't figure out how to pass an Argument like in the following scenario:

#include<stdio.h> void quit(const char*); int main(void){ const char *exit = "GoodBye"; void (*fptr)(const char*) = quit; (*fptr)(exit); return 0; } void quit(const char *s){ printf("\n\t%s\n",s); } 

This is how my program should work and it does, but when I make a text menu i just can't figure out how to do it:

#include<stdio.h> #include<stdlib.h> int update(void); int upgrade(void); int quit(void); void show(const char *question, const char **options, int (**actions)(void), int length); int main(void){ const char *question = "Choose Menu\n"; const char *options[3] = {"Update", "Upgrade", "Quit"}; int (*actions[3])(void) = {update,upgrade,quit}; show(question,options,actions,3); return 0; } int update(void){ printf("\n\tUpdating...\n"); return 1; } int upgrade(void){ printf("\n\tUpgrade...\n"); return 1; } int quit(void){ printf("\n\tQuit...\n"); return 0; } void show(const char *question, const char **options, int (**actions)(void), int length){ int choose = 0, repeat = 1; int (*act)(void); do{ printf("\n\t %s \n",question); for(int i=0;i<length;i++){ printf("%d. %s\n",(i+1),options[i]); } printf("\nPlease choose an Option: "); if((scanf("%d",&choose)) != 1){ printf("Error\n"); } act = actions[choose-1]; repeat = act(); if(act==0){ repeat = 0; } }while(repeat == 1); } 

Here I need to change the quit function (int quit(void); to int quit(char *s){};) like in the First example and call it with an argument like const char *exit = "GoodBye"; ==>> (*fptr)(exit);

I know that at this point my program takes only void as argument, but I done it only to illustrate the problem.

I'm very confused about this.

EDIT:

this int (*actions[3])(void) I think is an Array of Function pointers and all 3 function pointers takes void as argument, but I need to know if i can use one pointer to take an argument or i have to re-code the whole program.

4
  • Beware: your string exit confused me for a moment. There's a standard function exit() declared in <stdlib.h>. Your code would work even if you included <stdlib.h>, but you'd not be able to call the exit() function from within main() with the declaration of the string exit in main(). Not technically wrong — but IMO ill-advised. Commented Dec 10, 2015 at 15:32
  • int (*actions[3])(void), like any array, decays into a pointer to the first element. So the function can simply take a int (*)(void) parameter. Commented Dec 10, 2015 at 15:38
  • Presumably, if you're playing with pointers to functions at this level, you're also familiar with structures. You might do better with an array of structures (each containing a string and a pointer to function) rather than parallel arrays of strings and function pointers. All else apart, you can add information to the structure to indicate the calling convention of the function, if need be, which would be a pain to handle with another parallel array of information. Commented Dec 10, 2015 at 15:41
  • @JonathanLeffler I do know about exit function, I was illustrating the problem. Commented Dec 10, 2015 at 15:41

2 Answers 2

3

Since you have an array of function pointers, all the functions need to be of the same type. So at the very least each function should take a const char * (not all functions need to use it) and the array type should be changed to match.

If you want something more flexible, you can have the functions accept a single void * so each function can be passed a different parameter which it then casts to the appropriate type. This is how pthreads passes parameters to functions which start a new thread. You will lose some compile-time type checking with this, so be careful if you go this route.

EDIT:

An example of the latter:

#include<stdio.h> #include<stdlib.h> int update(void *); int upgrade(void *); int quit(void *); int main(void){ const char *question = "Choose Menu\n"; const char *options[3] = {"Update", "Upgrade", "Quit"}; int (*actions[3])(void *) = {update,upgrade,quit}; show(question,options,actions,3); return 0; } int update(void *unused){ printf("\n\tUpdating...\n"); return 1; } int upgrade(void *unused){ printf("\n\tUpgrade...\n"); return 1; } int quit(void *message){ printf("\n\tQuit...%s\n", (char *)message); return 0; } void show(const char *question, const char **options, int (**actions)(void *), int length){ ... if (act == quit) { repeat = act("GoodBye"); } else { repeat = act(NULL); } ... } 
Sign up to request clarification or add additional context in comments.

6 Comments

So this mean, that I have to recode the whole program because of that?
@Michi Maybe not the "whole program". You just need to add an extra parameter to each of the callback functions, change the type of the array, and add the logic to quit to handle the extra parameter.
Could you edit your Question with an example or to post a Demo?
@Michi Do you mean with the void * parameter?
a meant about what you said here You just need to add an extra parameter to each of the callback functions, change the type of the array, and add the logic to quit to handle the extra parameter. I really need an example to understand your logic.
|
2

Since you are using a an array of function pointers, you don't know which ones to take which arguments. But have You can avoid re-coding it by making the functions to take "unspecified number of arguments". i.e. Remove the void from as the parameter from function definitions and prototypes from of the function pointers and from the quit() function.

int quit(const char*); void show(const char *question, const char **options, int (**actions)(), int length); int main(void){ const char *question = "Choose Menu\n"; const char *options[3] = {"Update", "Upgrade", "Quit"}; int (*actions[3])() = {update,upgrade,quit}; ... } int quit(const char *msg){ printf("\n\tQuit...%s\n", msg); return 0; } void show(const char *question, const char **options, int (**actions)(), int length){ .... int (*act)(); .... } 

This works because C allows a function with no explicit parameters to take "unspecified number of arguments". Otherwise, you need to make all functions have similar signatures.

3 Comments

It may be worth noting that the code has to call the functions correctly, and must provide the correct number and types of arguments when the function is called, even if you forgo the checking that strict prototypes provides. That information has to be handled somehow in the show() function which calls the action functions. One reason for uniform interfaces is to avoid (some) complexity in the calling code.
With this code, this will compile: act = quit; act(); but will likely segfault due to the missing argument.
@dbush Yes. The caveats apply. May be, it's simple to rewrite in this simple code example of OP. But this is a viable solution. It's an alternative to rewriting a lot of code if you have 100s of callback functions with each taking different number of arguments.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.