Passing an argument to function pointer - c

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.

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);
}
...
}

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.

Related

Run function from structure variable

I try to run a function with a structure, because I work with a module who send callback so I want to execute the fuction to anwser to the callback.
typedef void (*bgs2_e_rx_callback)(unsigned char reason, unsigned short int n, char * data);
void bgs_callbacktest(char* data);
/*void test(int* ptest);
void test_tab(char* data,char* ptaille);
char* concat(const char *s1, const char *s2);
static void parse_numeric_rsp(char nb_values, char * data, unsigned long data_len,unsigned long * result);*/
struct teststruct{
short int i ;
bgs2_e_rx_callback callback;
void* param;
};
struct teststruct leteststruct ;
int main(){
printf("test for function in structure\n");
char txt[]="i'm a text";
leteststruct.param = txt;
leteststruct.callback = &bgs_callbacktest;
}
void bgs_callbacktest(char* data){
printf("your text: %s\n",leteststruct.param);
}
Compilation works good, but I don't see the message of the callback function.
You never call it! Edit your main like this:
int main(){
printf("test for function in structure\n");
char txt[]="i'm a text";
leteststruct.param = txt;
leteststruct.callback = bgs_callbacktest;
// Change the dummy parameters below with yours
leteststruct.callback(0x7f, 512, txt);
}
Then you will have it.

Function pointer pointing to functions with different number of arguments

How to handle assignment of the functions to one function pointer, each with different number of parameters ? The problem is that parameters differ in number and type. If possible give an example.
Function pointers can be cast in the same way as the other pointers. You will have a generic function pointer (similar to void * for storage types), and use it to hold/pass the address of the function. Before calling the function, you will need to cast it to the correct type.
Here is a working example:
#include <stdio.h>
typedef void (*generic_t)(void);
typedef int (*type2_t)(int);
typedef int (*type3_t)(int, char *s);
void test1(void) {
printf("Test 1\n");
}
int test2(int i) {
printf("Test 2 %i\n",i);
return i;
}
int test3(int i, char *s) {
printf("Test 3 %i, %s\n", i, s);
return i++;
}
int main(void) {
generic_t f1, f2, f3;
f1 = &test1;
f2 = (generic_t)&test2;
f3 = (generic_t)&test3;
f1();
int i = ((type2_t)f2)(10);
i = ((type3_t)f3)(20,"This is test");
}
In addition, you will need to implement a mechanism to recognize what is the type of function that the pointer is pointing to. One approach is to use a struct that holds the pointer and the enum of the type.
Another possibility is to create a union of different function pointer types:
union funptr {
void (*v)();
void (*vi)(int);
void (*vs)(char *);
int (*i)();
int (*ii)(int);
int (*iii)(int, int);
int (*is)(char *);
};
You can use void pointers to pass reference to the in and out parameters. Multiple parameters and return values you can wrap in the structs. The return value may return status.
Sometimes it used in low-level device drivers.
typedef int func(void *, void *);
func *fptr;
struct s1
{
int i;
char *s;
};
int test1(void *in, void *out)
{
printf("Test 1\n");
return 0;
}
int test2(void *in, void *out)
{
int *i = in;
printf("Test 2 %i\n", *i);
return *i;
}
int test3(void *in, void *out)
{
struct s1 *s = in;
printf("Test 3 %i, %s\n", s -> i, s -> s);
return ++s -> i;
}
int main(void)
{
fptr = test1;
fptr(NULL, NULL);
fptr = test2;
fptr((int[]){10}, NULL);
fptr = test3;
printf("Returned value: %d\n", fptr(&(struct s1){20,"This is test"}, NULL));
}
You have to declare a new function pointer type for every different signature that you need to handle.

How do you pass a character array

I want to pass an array of characters i.e. a String in c
int main()
{
const char c[]="Joseph";
TestWord(&c,&c);
return 0;
}
int TestWord(char tiles[], char word[])
{
return tiles;
}
#include <stdio.h>
char *TestWord(char tiles[], char word[]);
int main()
{
char c[]="Joseph";
char r;
r = *TestWord(c,c);
return 0;
}
char *TestWord(char tiles[], char word[])
{
return tiles;
}
You pass through the arrays without the & as arrays don't need those, as they are already somewhat like pointers, just like how you would scanf an array without the & symbol.
Don't forget that if you are returning tiles that you should save that in a variable.
you could pass a string(character array) in C in many ways.
This code passes the string a to the function PRINT. Note that in this method the base address of the array is sent to the function.
#include<stdio.h>
void PRINT(char b[])
{
printf("%s",b);
}
int main()
{
char a[]="hello";
PRINT(a);
return 0;
}

qsort of struct array not working

I am trying to sort a struct run array called results by a char, but when I print the array, nothing is sorted. Have a look at this:
struct run {
char name[20], weekday[4], month[10];
(And some more...)
};
typedef struct run run;
int name_compare(const void *a, const void *b)
{
run *run1 = *(run **)a;
run *run2 = *(run **)b;
return strcmp(run1->name, run2->name);
}
int count_number_of_different_persons(run results[])
{
int i = 0;
qsort(results, sizeof(results) / sizeof(run), sizeof(run), name_compare);
for(i = 0; i <= 999; i++)
{
printf("%s\n", results[i].name);
}
// not done with this function yet, just return 0
return 0;
}
The output from the above is just a list of names in the order they were originally placed
int count_number_of_different_persons(run results[])
This doesn't really let you use sizeof on the array, because array is decayed to pointer.
This
run *run1 = *(run **)a;
also looks weird, shouldn't it be
run *run1 = (run*)a;
?
One problem is in name_compare. Try this instead:
int name_compare(const void *a, const void *b)
{
run *run1 = (run *)a;
run *run2 = (run *)b;
return strcmp(run1->name, run2->name);
}
Check the following code:
As #michel mentioned, sizeof(array) provides size of the pointer, not the size of the array itself, as while passing array it is treated as a pointer. Hence either send the number of elements to the function count_number_of_different_persons or define a MACRO of number of elements. Hope this helps. :).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOE 3
struct run
{
char name[20];
};
typedef struct run run;
int name_compare (const void *a, const void *b )
{
return strcmp (((run *)a)->name, ((run *)b)->name);
}
int count_number_of_different_persons(run results[], int noOfElements)
{
int i=0;
qsort(results, noOfElements, sizeof (run), name_compare);
for (i=0; i<noOfElements; i++)
printf ("%s\n",results[i].name);
}
int main ( int argc, char * argv[])
{
run a, b, c;
run arg[NOE];
strcpy (a.name, "love");
strcpy (b.name, "you");
strcpy (c.name, "i");
arg[0] = a;
arg[1] = b;
arg[2] = c;
count_number_of_different_persons(arg, sizeof(arg)/sizeof(run));
};

Array-strings sorted using qSort in C

the question is simple: there is some way that the ordered array that returns me the "qsort", is returned in reverse, ie I want to avoid the use of any auxiliary array to invest the resulting array using qsort.
this is my code, which reads from standard input strings to be sorted, and uses a comparison function for sorting.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcasecmp(*ia, *ib);
/* strcmp functions works exactly as expected from
comparison function */
}
Thanks in advance for your response, sorry for my English
int main (int argc, char *argv [])
{
int number;
char temp [4000];
printf("input number: ");
scanf("%d",&number);
char* array_string [number];
int i;
for (i=0;i<number;i++) {
scanf(" %[^\n]", temp);
array_string [i] = (char*)malloc((strlen(temp)+1)*sizeof(char));
strcpy(array_string[i], temp);
}
size_t large = sizeof(array_string) / sizeof(char *);
qsort(array_string,large ,sizeof(char *) ,cstring_cmp );
printf ("\n");
printf ("the sorted array list is:\n");
for (i=0;i<large;i++)
printf("%s\n", array_string [i]);
return 0;
}
Have you just tried reversing the order of parameters to strcasecmp?
return strcasecmp(*ib, *ia);
Does this do what you want?
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return -strcasecmp(*ia, *ib);
/* return the negative of the normal comparison */
}

Resources