C语言_函数指针

回顾指针概念

	int a, b = 0;
	int* ip = &a;
	int** sp = &ip;

	int ar[10] = {
     };
	ip = ar;

	int(*par)[10] = &ar;
	int* pbr[10] = {
     };
	int* (*sbr)[10] = &pbr;
	//需要定义一个指向一维整型数组的指针,才能指向pbr数组

函数指针

//int fun(int, int); //= nullptr错误//函数声明
int (*pfun)(int, int) = nullptr;//函数指针变量的定义
int x = 10;
int y = 20;
int z = 0;
pfun = Add_Int;
z = Add_Int(x, y);
z = pfun(x, y);//新的函数调用规则
z = (*pfun)(x, y);//旧有的函数调用规则


pfun = Sub_Int;
z = pfun(x, y);

上面的代码可以由下面这个图来表示出来
C语言_函数指针_第1张图片

注意对于函数指针不能计算所指函数的大小,可以计算指针大小

sizeof(pfun);//√
//sizeof(*pfun);//x

函数指针可以作为函数的参数传到函数中

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

int Sub_Int(int a, int b) {
     
	return a - b;
}

void fun(int a, int b, int(*pfun)(int, int)) {
     
	assert(pfun != nullptr);
	int c = pfun(a, b);
	printf("%d\n", c);

}

int main() {
     
	fun(x, y, Add_Int);
	fun(x, y, Sub_Int);
}


回调函数

函数指针在作为函数参数的时候,可以采用函数声明的方式作为形参,这是一个比较特殊的点,比如下面两个函数参数中函数指针的写法是等价的,虽然这里面的int pfun(int, int)是函数声明,但是确实正确的允许的

void fun(int a, int b, int pfun(int, int)) {
     
	assert(pfun != nullptr);
	int c = pfun(a, b);
	printf("%d\n", c);

}

void fun(int a, int b, int(*pfun)(int, int)) {
     
	assert(pfun != nullptr);
	int c = pfun(a, b);
	printf("%d\n", c);

}

回调函数的用处

void* Print_Int(void* p)
{
     
	int* ip = (int*)p;
	printf("%d ", *ip);
	return ip + 1;
}
void* Print_Double(void* p)
{
     
	double* dp = (double*)p;
	printf("%lf ", *dp);
	return dp + 1;
}
void* Print_Char(void* p)
{
     
	char* cp = (char*)p;
	printf("%c ", *cp);
	return cp + 1;
}
void Print_Array(void* br, int n, void * (*fp) (void *) )
{
     
	for (int i = 0; i < n; ++i)
	{
     
		br = (*fp)(br);
	}
	printf("\n");
}
int main()
{
     
	int ar[] = {
      12,23,34,45,56,67,78 };
	int in = sizeof(ar) / sizeof(ar[0]);
	double dx[] = {
      1.2,2.3,3.4,4.5,5.6,6.7,7.8,8.9 };
	int dn = sizeof(dx) / sizeof(dx[0]);
	char str[] = {
      "yhpinghello" };
	char cn = strlen(str);
	Print_Array(ar, in,Print_Int);
	Print_Array(dx, dn,Print_Double);

	Print_Array(str, cn, Print_Char);

	return 0;
}

打印数组,数组类型不同,这个时候可以定义几个不同函数类型的函数,然后在打印数组的函数内传递函数指针参数,使得数组顺利打印出来,这里面就是函数回调的应用,是函数指针泛型函数的应用。

函数指针返回类型

函数指针也可以作为函数返回类型来使用,如下面这段代码,但是由于函数指针如果作为函数返回类型来使用的话,会十分复杂,让人眼花缭乱,所以这里面采用typedef定义函数指针类型,方便了函数指针作为返回类型来使用

typedef int(*PFUN)(int, int);
//typedef int (*)(int, int) SFUN;//error
int (*g_fun)(int, int) = nullptr;
//int(*GetPFun(int (*fp)(int, int)))(int, int)
PFUN GetPFun(PFUN fp)
{
     
	int (*old)(int, int) = g_fun;
	g_fun = fp;
	return old;
}

函数指针应用例子

输入数字1-7,打印其对应的星期数

void PrintMon()	{
     printf("Monday\n"); }
void PrintTue() {
      printf("Tuesday\n"); }
void PrintWed()	{
      printf("Wednesday\n"); }
void PrintThu(){
      printf("Thursday\n"); }
void PrintFri()	{
     printf("Friday\n");  }
void PrintSat()	 {
      	printf("Saturday\n");}
void PrintSun(){
        	printf("Sunday\n");	 }
void (*pfun[])() = {
      
	PrintMon,
	PrintTue,
	PrintWed,
	PrintThu,
	PrintFri,
	PrintSat,
	PrintSun 
};

void Print(int i)
{
     
	assert(i >= 1 && i <= 7);
	(*pfun[i - 1])();	  //pfun[i - 1]();
}
int main()
{
     
	int message;
	while (scanf_s("%d", &message), message != -1)
	{
     
		Print(message);
	}
	return 0;
}

在vc 6.0++中有下面这个有意思的情况,可以根据函数指针地址,将其强转为函数对象,然后解引用调用该函数,也能调用成功。如下面这段代码:

void fun()
{
     
	printf("yhping hello \n");
}

int main()
{
     
	int a = 10;
	void (*pfun)() = NULL;

	pfun = (void (*)())0x0040b760;

	(*pfun)();

	(*((void (*)())0x0040b760))();

	(*(void(*)())0))();


	return 0;
}

你可能感兴趣的:(C语言)