如何在 C 语言中使用函数指针数组?

我应该如何在C中使用函数指针数组?

如何初始化它们?

344980 次浏览

你有一个很好的例子here(函数指针数组),有语法的详细

int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);


int (*p[4]) (int x, int y);


int main(void)
{
int result;
int i, j, op;


p[0] = sum; /* address of sum() */
p[1] = subtract; /* address of subtract() */
p[2] = mul; /* address of mul() */
p[3] = div; /* address of div() */
[...]

要调用其中一个函数指针:

result = (*p[op]) (i, j); // op being the index of one of the four functions

上面的答案可能会帮助你,但你也可能想知道如何使用函数指针数组。

void fun1()
{


}


void fun2()
{


}


void fun3()
{


}


void (*func_ptr[3])() = {fun1, fun2, fun3};


main()
{
int option;




printf("\nEnter function number you want");
printf("\nYou should not enter other than 0 , 1, 2"); /* because we have only 3 functions */
scanf("%d",&option);


if((option>=0)&&(option<=2))
{
(*func_ptr[option])();
}


return 0;
}

您只能将具有相同返回类型和相同参数类型的函数的地址分配给单个函数指针数组。

如果上面所有函数都具有相同数量的相同类型的参数,您还可以像下面这样传递参数。

  (*func_ptr[option])(argu1);

注意:在数组中,函数指针的编号将从0开始,与一般数组相同。所以在上面的例子中,如果option=0可以调用fun1,如果option=1可以调用fun2,如果option=2可以调用fun3

哦,有很多例子。看看glib或gtk中的任何东西。 你可以在这里看到函数指针的作用。< / p >

这里是gtk_button的初始化。


static void
gtk_button_class_init (GtkButtonClass *klass)
{
GObjectClass *gobject_class;
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;


gobject_class = G_OBJECT_CLASS (klass);
object_class = (GtkObjectClass*) klass;
widget_class = (GtkWidgetClass*) klass;
container_class = (GtkContainerClass*) klass;


gobject_class->constructor = gtk_button_constructor;
gobject_class->set_property = gtk_button_set_property;
gobject_class->get_property = gtk_button_get_property;


在gtkobject.h中,你会发现以下声明:


struct _GtkObjectClass
{
GInitiallyUnownedClass parent_class;


/* Non overridable class methods to set and get per class arguments */
void (*set_arg) (GtkObject *object,
GtkArg    *arg,
guint      arg_id);
void (*get_arg) (GtkObject *object,
GtkArg    *arg,
guint      arg_id);


/* Default signal handler for the ::destroy signal, which is
*  invoked to request that references to the widget be dropped.
*  If an object class overrides destroy() in order to perform class
*  specific destruction then it must still invoke its superclass'
*  implementation of the method after it is finished with its
*  own cleanup. (See gtk_widget_real_destroy() for an example of
*  how to do this).
*/
void (*destroy)  (GtkObject *object);
};

(*set_arg)这个东西是一个指向函数的指针,它可以在一些派生类中被赋给另一个实现。

你经常会看到这样的东西

struct function_table {
char *name;
void (*some_fun)(int arg1, double arg2);
};


void function1(int  arg1, double arg2)....




struct function_table my_table [] = {
{"function1", function1},
...

因此,您可以通过名称进入表并调用“associated”函数。

或者您可能使用一个哈希表,将函数放入其中并“按名称”调用它。

< p >的问候
弗里德里希< / p >

下面是你如何使用它:

New_Fun.h

#ifndef NEW_FUN_H_
#define NEW_FUN_H_


#include <stdio.h>


typedef int speed;
speed fun(int x);


enum fp {
f1, f2, f3, f4, f5
};


void F1();
void F2();
void F3();
void F4();
void F5();
#endif

New_Fun.c

#include "New_Fun.h"


speed fun(int x)
{
int Vel;
Vel = x;
return Vel;
}


void F1()
{
printf("From F1\n");
}


void F2()
{
printf("From F2\n");
}


void F3()
{
printf("From F3\n");
}


void F4()
{
printf("From F4\n");
}


void F5()
{
printf("From F5\n");
}

c

#include <stdio.h>
#include "New_Fun.h"


int main()
{
int (*F_P)(int y);
void (*F_A[5])() = { F1, F2, F3, F4, F5 };    // if it is int the pointer incompatible is bound to happen
int xyz, i;


printf("Hello Function Pointer!\n");
F_P = fun;
xyz = F_P(5);
printf("The Value is %d\n", xyz);
//(*F_A[5]) = { F1, F2, F3, F4, F5 };
for (i = 0; i < 5; i++)
{
F_A[i]();
}
printf("\n\n");
F_A[f1]();
F_A[f2]();
F_A[f3]();
F_A[f4]();
return 0;
}

我希望这有助于理解Function Pointer.

这个“答案”更像是对VonC答案的补充;注意,语法可以通过类型定义来简化,并且可以使用聚合初始化:

typedef int FUNC(int, int);


FUNC sum, subtract, mul, div;
FUNC *p[4] = { sum, subtract, mul, div };


int main(void)
{
int result;
int i = 2, j = 3, op = 2;  // 2: mul


result = p[op](i, j);   // = 6
}


// maybe even in another file
int sum(int a, int b) { return a+b; }
int subtract(int a, int b) { return a-b; }
int mul(int a, int b) { return a*b; }
int div(int a, int b) { return a/b; }

这个问题已经有很好的例子来回答了。唯一可能缺少的例子是函数返回指针的例子。我用这个写了另一个例子,并添加了很多注释,以防有人发现它有帮助:

#include <stdio.h>


char * func1(char *a) {
*a = 'b';
return a;
}


char * func2(char *a) {
*a = 'c';
return a;
}


int main() {
char a = 'a';
/* declare array of function pointers
* the function pointer types are char * name(char *)
* A pointer to this type of function would be just
* put * before name, and parenthesis around *name:
*   char * (*name)(char *)
* An array of these pointers is the same with [x]
*/
char * (*functions[2])(char *) = {func1, func2};
printf("%c, ", a);
/* the functions return a pointer, so I need to deference pointer
* Thats why the * in front of the parenthesis (in case it confused you)
*/
printf("%c, ", *(*functions[0])(&a));
printf("%c\n", *(*functions[1])(&a));


a = 'a';
/* creating 'name' for a function pointer type
* funcp is equivalent to type char *(*funcname)(char *)
*/
typedef char *(*funcp)(char *);
/* Now the declaration of the array of function pointers
* becomes easier
*/
funcp functions2[2] = {func1, func2};


printf("%c, ", a);
printf("%c, ", *(*functions2[0])(&a));
printf("%c\n", *(*functions2[1])(&a));


return 0;
}

这应该是一个简短的&简单复制&粘贴一段上述响应的代码示例。希望这能有所帮助。

#include <iostream>
using namespace std;


#define DBG_PRINT(x) do { std::printf("Line:%-4d" "  %15s = %-10d\n", __LINE__, #x, x); } while(0);


void F0(){ printf("Print F%d\n", 0); }
void F1(){ printf("Print F%d\n", 1); }
void F2(){ printf("Print F%d\n", 2); }
void F3(){ printf("Print F%d\n", 3); }
void F4(){ printf("Print F%d\n", 4); }
void (*fArrVoid[N_FUNC])() = {F0, F1, F2, F3, F4};


int Sum(int a, int b){ return(a+b); }
int Sub(int a, int b){ return(a-b); }
int Mul(int a, int b){ return(a*b); }
int Div(int a, int b){ return(a/b); }
int (*fArrArgs[4])(int a, int b) = {Sum, Sub, Mul, Div};


int main(){
for(int i = 0; i < 5; i++)  (*fArrVoid[i])();
printf("\n");


DBG_PRINT((*fArrArgs[0])(3,2))
DBG_PRINT((*fArrArgs[1])(3,2))
DBG_PRINT((*fArrArgs[2])(3,2))
DBG_PRINT((*fArrArgs[3])(3,2))


return(0);
}

这个简单的例子,多维数组的函数指针”:

void one( int a, int b){    printf(" \n[ ONE ]  a =  %d   b = %d",a,b);}
void two( int a, int b){    printf(" \n[ TWO ]  a =  %d   b = %d",a,b);}
void three( int a, int b){    printf("\n [ THREE ]  a =  %d   b = %d",a,b);}
void four( int a, int b){    printf(" \n[ FOUR ]  a =  %d   b = %d",a,b);}
void five( int a, int b){    printf(" \n [ FIVE ]  a =  %d   b = %d",a,b);}
void(*p[2][2])(int,int)   ;
int main()
{
int i,j;
printf("multidimensional array with function pointers\n");


p[0][0] = one;    p[0][1] = two;    p[1][0] = three;    p[1][1] = four;
for (  i  = 1 ; i >=0; i--)
for (  j  = 0 ; j <2; j++)
(*p[i][j])( (i, i*j);
return 0;
}

最简单的解决方案是给出你想要的最终向量的地址,并在函数中修改它。

void calculation(double result[] ){  //do the calculation on result


result[0] = 10+5;
result[1] = 10 +6;
.....
}


int main(){


double result[10] = {0}; //this is the vector of the results


calculation(result);  //this will modify result
}

可以这样使用它:

//! Define:
#define F_NUM 3
int (*pFunctions[F_NUM])(void * arg);


//! Initialise:
int someFunction(void * arg) {
int a= *((int*)arg);
return a*a;
}


pFunctions[0]= someFunction;


//! Use:
int someMethod(int idx, void * arg, int * result) {
int done= 0;
if (idx < F_NUM && pFunctions[idx] != NULL) {
*result= pFunctions[idx](arg);
done= 1;
}
return done;
}


int x= 2;
int z= 0;
someMethod(0, (void*)&x, &z);
assert(z == 4);

下面是一个简单的例子:

jump_table.c

int func1(int arg)  { return arg + 1; }
int func2(int arg)  { return arg + 2; }
int func3(int arg)  { return arg + 3; }
int func4(int arg)  { return arg + 4; }
int func5(int arg)  { return arg + 5; }
int func6(int arg)  { return arg + 6; }
int func7(int arg)  { return arg + 7; }
int func8(int arg)  { return arg + 8; }
int func9(int arg)  { return arg + 9; }
int func10(int arg) { return arg + 10; }


int (*jump_table[10])(int) = { func1, func2, func3, func4, func5,
func6, func7, func8, func9, func10 };
    

int main(void) {
int index = 2;
int argument = 42;
int result = (*jump_table[index])(argument);
// result is 45
}

存储在数组中的所有函数必须具有相同的签名。这仅仅意味着它们必须返回相同的类型(例如int)并且具有相同的参数(在上面的例子中只有一个int)。


在c++中,你可以用静态类方法(但不能用实例方法)做同样的事情。例如,你可以在上面的数组中使用MyClass::myStaticMethod,而不是MyClass::myInstanceMethodinstance.myInstanceMethod:

class MyClass {
public:
static int myStaticMethod(int foo)   { return foo + 17; }
int        myInstanceMethod(int bar) { return bar + 17; }
}


MyClass instance;
#include <iostream>
using namespace std;
    

int sum (int , int);
int prod (int , int);
    

int main()
{
int (*p[2])(int , int ) = {sum,prod};
    

cout << (*p[0])(2,3) << endl;
cout << (*p[1])(2,3) << endl;
}
    

int sum (int a , int b)
{
return a+b;
}
    

int prod (int a, int b)
{
return a*b;
}