出淤泥而不染,濯清涟而不妖。——周敦颐
回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条 件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。 那我们想要理解到底怎么才算是回调函数,光是看定义肯定是不够用的,我们得结合实际才能有足够深入的了解。
int add(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;
}
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 1;
do
{
printf("*************************");
printf(" 1:add*********2:div*****");
printf(" 3:mul*********0:exit****");
printf("*************************");
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
calc(add);
break;
case 2:
calc(sub);
break;
case 3:
calc(mul);
break;
case 4:
calc(div);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
} while (input);
}
return 0;
}
在这句话中的这一段,是最重要的。也是回调函数的使用,从而避免了冗长的代码。
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}`
利用这句话,减少了在不同case情况下,每次都要写的这段代码。
int x, y;
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
当然,如果现在回来看这里的使用回调函数,看那句定义的话,肯定能更深的理解这句话。 把函数的指针当作为参数传递给另一个函数时,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。 除此之外,还必须掌握另一个很重要的并且容易出错的地方,那就是,函数指针的使用。 并且,在这里我们也可以感受到,地址的作用,如果这里没有地址的话,那将不再可能实现直接的调用。 那从这里不经想起,数组指针,指针数组那些有些模糊的定义。
其实指针类型不知有数组,还有简单的,更容易理解的整型指针,字符指针等基本的指针。例子的话就不举了,但是要注意的是在char*的使用时,写为这样子
const char* ptr="hello world";
认为把整个都存起来,但是其实只是把这段字符串的首字符的地址放在了指针ptr中。
#include<stdio.h>
int main()
{
char str1[] = "hello";
char str2[] = "hello";
const char* str3 = "hello";
const char* str4 = "hello";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
那为什么,str1和str2是不同的呢,其实就是因为,在创建不同的数组的时候,是在不同位置开辟的,所以即使是数组名,是h,看上去好像是一样的,但是,那本质这段话的意思其实是在内存中开辟的空间的地址,两个数组也不可能重复开辟一段空间,所以,str1和str2不可能相等。 那为什么str3和str4是相等的呢? 那是因为str3和str4是指针,指向开辟的一段空间的首字母地址,并且常量字符串是不会被修改的,而且也不会为两个指针,就把一个常量,开辟两个空间,计算机一定会节省空间的。
我们可以先由(2、1)中的内容,知道什么指针是怎么表示的,那么数组指针呢?应该是可以推断出其实就是存放数组的指针,那么数组也是有不同的大小小的,那有怎么表示的呢?
int* p1[10];
int (*p2)[10];
可以根据前面的写法猜一猜,感受一下,到底哪一个更像是数组指针? 注意:[]的优先级是高于*的。 正确的答案其实是p2那个表达形式,因为是指针,所有用(*p)来确保,先是指针,然后才轮到数组。 那么这句话是什么意思呢? 意思就是,一个p2的指针指向一个整型数组,指向一个大小是10个整型的数组。
这里,也可以通过以前讲过的整型数组来帮助我们理解。那么其实数组指针就是存放指针的数组。 再根据上面一段中,展示的优先级,其实是可以更好的理解这里就是先是数组,然后才轮到指针的。
总结:其实分清主谓语也可以帮助区别,就比如说好孩子,好是形容词,而孩子才是真正重要的主语。所以数组指针,就是指针,用来指向数组的。而指针数组,就是一个数组,用来存放指针的。
函数指针和数组名其实差不多,当是直接用函数名的时候就是函数的首地址,而&函数名就是整个函数的地址。
当然,在这里,x和y都是可以不用写出来的,写也是可以的。 下面来一段使用函数指针的例子。
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));
printf("%d\n", pf3(3, 5));//两种写法都是可以的
return 0;
}
这是啥意思呢? 其实可以从里面向外面去看,要抓住里面的*符号,其实这就是一个函数指针,只不过是一个空的名字,并且函数还没有参数。而向外看,使用了void的,就是把这函数强制类型转换。并且又因为内部函数没有参数,所以在最后的一个空里面,也是没有参数。这就是这段大妈的全部含义了。
那这句话呢? 其实应该是看成两部分,可以认为是代码的“复合函数”。 整体上来看,应该是
void (*)(int )
那么第一段括号内,就是关于signal的函数的声明 包含了两个成分,第一个是int类型,而第二个是void(*)(int)的函数
根据前面提到过的帮助判断的方法,可以也对这种进行判断。就比如下面这几个,来判断看看哪个是真正的指针数组。
parr1是真正的函数指针数组。 那么这些有什么用呢? 其实在下面一段就可以用到了!
请看下面代码!
#include <stdio.h>
int add(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 main()
{
int x, y;
int input = 1;
int ret = 0;
int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);
printf("ret = %d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输⼊有误\n");
}
} while (input);
return 0;
}
这里就是用到了函数指针数组!! 同时,那个就是转移表!