I have a create function that I want to pass a function pointer, however I want the function pointer to be able to call either of the functions below the problem that I am having is that each one return a different type. But when I pass the function pointer I have to specify the return type of the function pointer. Is this correct? I thought using a void pointer in the would solve the return type problem, but now I can't call the function pointer. To clarify I want to pass either populateMonsters
or populateClassesTaken
into create
and be able to call them within create
.
typedef struct node{
void * data;
struct node* next;
} node;
typedef struct MonsterAttacks{
unsigned int attackID;
char monsterName[41];
char attackLocation[41];
unsigned int numOfVictims;
}MonsterAttacks;
typedef struct ClassesTaken{
unsigned int classID;
char semester[41];
unsigned int year;
unsigned int numberOfUnits;
char grade[10];
}ClassesTaken;
unsigned int idM = 1;
MonsterAttacks * populateMonsters(){
MonsterAttacks *m = NULL;
m->attackID = idM;
printf("Enter the name for the Monster \n");
scanf("%40s",m->monsterName);
puts("What is his/her attack location?");
scanf("%40s",m->attackLocation);
puts("What are the number of victims this monster has demolished?");
scanf("%ud", &m->numOfVictims);
//attackID is assigned and id when node is created
idM++;
return m;
}
unsigned int idC = 1;
ClassesTaken* populateClassesTaken(){
ClassesTaken *c = NULL;
c->classID = idC;
scanf("What semester was the class taken in? %40s",c->semester);
scanf("In what year? %ud", &c->year);
scanf("How many units was the class? %ud", &c->numberOfUnits);
scanf("What was your grade in the class? %9s", c->grade);
idC++;
return c;
}
node* create(node* next, void *fp)
{
node* new_node = (node*)malloc(sizeof(node));
if(new_node == NULL)
{
printf("Error creating a new node.\n");
exit(0);
}
void *data = (*fp)();
}
int main(void)
{
node* tmp = NULL;
MonsterAttacks* (*fp)() = &populateMonsters;
create(tmp, *fp);
}
First of all, it goes without saying that you can't write code like ClassesTaken *c = NULL; c->classID = idC;
ClassesTaken *c = NULL; c->classID = idC;
. If you don't understand why you can't, you need to go back to learning the very basics of pointers, as explained here: Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
As for the different functions - the fact that they are different function types is a clear indication that this design doesn't make sense. If you wish to use generic function pointers, you need to define a uniform function format, such as for example void* func (void)
.
You cannot use void*
as a generic function pointers. It is only defined for use with pointers to objects, not to functions. Code such as create(tmp, *fp);
where fp is a function pointer and the function expects a void*
is not valid standard C and should not compile, unless you are using non-standard compiler extensions.
Notably, you should never declare functions with an empty parenthis ()
in C. This is an obsolete language feature. (Unlike C++, where this is fine and encouraged.)
Replace:
node* create(node* next, void *fp)
{
with:
node* create(node* next, void* (*fp)())
{
and
create(tmp, *fp);
with
create(tmp, (void*)fp); //[updated]
Your populateMonsters() causes a Segmentation fault. I replaced its code with fputs("In populateMonsters\\n", stderr);
and it appeared to work:
$ ./a.out
In populateMonsters
There is still a problem in populateMonsters()
and populateClassesTaken()
. You want to fill the structures with user input but you never allocate the structures (neither on heap nor on stack). Therefore you get a Segmentation fault. Here is my code without the typedefs, include, ...
typedef void*(*myFunctionInterface)(void);
MonsterAttacks * populateMonsters (){
MonsterAttacks *m = (MonsterAttacks*)malloc(sizeof(MonsterAttacks));
if (m == NULL){
printf("Error creating MonsterAttacks");
exit (-1);
}
m->attackID = idM;
printf ("Enter the name for the Monster \n");
scanf ("%40s", m->monsterName);
puts ("What is his/her attack location?");
scanf ("%40s", m->attackLocation);
puts ("What are the number of victims this monster has demolished?");
scanf ("%ud", &m->numOfVictims);
//attackID is assigned and id when node is created
idM++;
return m;
}
unsigned int idC = 1;
ClassesTaken * populateClassesTaken (){
ClassesTaken *c = (ClassesTaken*)malloc(sizeof(ClassesTaken));
if (c == NULL){
printf("Error creating ClassesTaken");
exit(-2);
}
c->classID = idC;
scanf ("What semester was the class taken in? %40s", c->semester);
scanf ("In what year? %ud", &c->year);
scanf ("How many units was the class? %ud", &c->numberOfUnits);
scanf ("What was your grade in the class? %9s", c->grade);
idC++;
return c;
}
node * create (node * next, void *(*fp) ()){
node *new_node = (node *) malloc (sizeof (node));
if (new_node == NULL)
{
printf ("Error creating a new node.\n");
exit (-3);
}
void *data = fp();
new_node->data = data;
return new_node;
}
int main (void) {
node *tmp = NULL;
MonsterAttacks *(*fp_M) () = &populateMonsters;
ClassesTaken *(*fp_C) () = &populateClassesTaken;
create (tmp, (myFunctionInterface)fp_M);
}
It is also not a good style to return 0 in case of an error. 0 usually means that everything is ok. Hence, I changed the exit-values to some different negative numbers to distinguish between the errors
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.