C语言函数指针和回调函数
函数指针
通常我们可以将指针指向某类型的变量,称为类型指针(如,整型指针)。若将一个指针指向函数,则称为函数指针。
函数名的意义
函数名代表函数的入口地址,同样的,我们可以通过根据该地址进行函数调用,而非直接调用函数名。
void test001(){
printf("hello, world");
} int main(){ printf("函数入口地址:%d", test001);//qt中的函数入口地址不会变,C中会变,这里仅为了说明问题
//test001();
int *testADD = (int *);//将地址转化为int型指针
void(*myfunc)() = testADD;//将函数写成函数指针,有些书上会写&testADD
myfunc(); //调用函数指针
system("pause");
return ;
}
另外,还有以下结论:
(1)test001的函数名与myfunc函数指针都是一样的,即都是函数指针。test001函数名是一个函数指针常量,而myfunc是一个函数指针变量,这是它们的关系。
int test001(int a, char b){
printf("hello, world\n");
return ;
} int main(){ int(*myFun)(int, char) = test001;
myFun = test001; //下面四种表达式的结果是相同的
int a = ;
char b = 's';
myFun(a, b);
(*myFun)(a, b);
test001(a, b);
(*test001)(a, b); system("pause");
return ;
}
(2)testADD和&testADD的值一样,但表达的含义不同,与数组名和“&数组名”类似,详见指针和数组的关系。
定义函数指针
定义函数指针最简单的是直接定义函数指针变量,另外还有定义函数类型和定义函数指针类型。
int test001(int a, char b){
printf("hello, world\n");
return ;
} void test002(){ //定义函数类型
typedef int(Fun)(int, char);
Fun *funFir = test001; //定义函数指针类型
typedef int(*FunP)(int, char);
FunP funSec = test001; //定义函数指针变量
int(*funThi)(int, char) = NULL;//若报错,在强制转型,(int(*)(int , char))NULL
funThi = test001;
}
函数指针用于形参
这种用法通常出现在回调函数中,一般回调函数用于定制操作,下面的例子将说明如何进行定制操作
/*
-----------------------
函数指针用作另一个函数的参数
-----------------------
*/
int con1(int a, int b){
return a + b;
} int con2(int a, int b){
return a - b;
} int con3(int a, int b){
return a + b + ;
} //在函数体中显式调用函数,将失去灵活性
//尽管我可以用switch实现三种con的切换
void doc(){
int a = ;
int b = ;
int ret = con1(a, b);
} //用如下的调用方式,调用者并不知道调用的哪个函数
//因此根据函数指针的函数原型可以自己实现新函数,并进行调用
int doc_p(int(*temp)(int ,char)){
int a = ;
int b = ;
int ret = temp(a,b);
return ret;
} /*
---------------------
函数指针数组
---------------------
*/
void func1(){
printf("a");
}
void func2(){
printf("a");
}
void func3(){
printf("a");
} void test003(){
int(*func[])();
func[] = func1;
func[] = func2;
func[] = func3; for (int i = ; i < ; ++i)
{
func[i];
}
}
为什么我们要把函数作为参数来调用呢,直接在函数体里面调用不好吗?
在这个意义上,“把函数做成参数”和“把变量做成参数”目的是一致的,就是以不变应万变。形参是不变的,而实参是可以定制的。唯一不同的是,普通的实参可以由计算机程序自动产生,而函数这种参数计算机程序是无法自己写出来的,因为函数本身就是程序,它必须由人来写。所以对于回调函数这种参数而言,它的“变”在于人有变或者人的需求有变。
回调函数
回调函数和普通函数完成的功能是一样的,但回调函数更灵活,普通函数在函数体中调用,失去了变量的灵活性,有点类似于模板编程。
(1)首先是通过内存偏移,访问数组的各元素地址,两种方法的结果相同
void printAll(void *arr, int eleSize, int len){ char *start = (char*)arr; //强制转型
for (int i = ; i < len; ++i){
printf("%d\n", start+i*eleSize);//内存偏移
}
} void test004(){
int arr[] = {,,,,};
printAll(arr, sizeof(int), );
printf("-------------------\n");
for (int i = ; i < ; ++i){
printf("%d\n", &arr[i]);
}
} int main(){
test004(); system("pause");
return ;
}
(2)对上面的函数用函数指针进行改写
//添加函数指针作形参,必须写明变量名
void printAll(void *arr, int eleSize, int len, void(*print)(void *data)){ char *start = (char*)arr; //强制转型
for (int i = ; i < len; ++i){
char *eleAddr = start + i*eleSize;
print(eleAddr);
//print(start+i*eleSize);
}
} //自定义的被调用函数
void Myprint(void * data){
int *p = (int *)data;
printf("%d\n", *p);
} void test004(){
int arr[] = {,,,,};
printAll(arr, sizeof(int), , Myprint);
} int main(){
test004(); system("pause");
return ;
}
(3)对上面的函数指针添加自定义的数据类型
//添加函数指针作形参,必须写明变量名
void printAll(void *arr, int eleSize, int len, void(*print)(void *data)){ char *start = (char*)arr; //强制转型
for (int i = ; i < len; ++i){
char *eleAddr = start + i*eleSize;
print(eleAddr);
//print(start+i*eleSize);
}
} //自定义的被调用函数
void Myprint(void * data){
int *p = (int *)data;
printf("%d\n", *p);
} struct Person{
char name[];
int age;
}; //添加自定义的数据类型打印函数
void MyprintStruct(void * data){
struct Person *p = (struct Person *)data;
printf("%s,%d\n", p->name, p->age);
} void test004(){
int arr[] = {,,,,};
printAll(arr, sizeof(int), , Myprint); struct Person person[] = {
{"aaa", },
{"bbb", }
};
printAll(person, sizeof(struct Person), , MyprintStruct); } int main(){
test004(); system("pause");
return ;
}
回调函数最大的优势在于灵活操作,可以实现用户定制的函数,降低耦合性,实现多样性。
C语言函数指针和回调函数的更多相关文章
- VC++的函数指针和回调函数 及友元函数
什么是函数指针 函数指针是指向函数的指针变量.也就是说,它是一个指针变量,而且该指针指向一个函数. 对于指针变量来说,它的值是它指向的变量的地址.举个例子:指针变量pi是指向一个整型变量i的指针,则变 ...
- 深入浅出剖析C语言函数指针与回调函数(一)【转】
本文转载自:http://blog.csdn.net/morixinguan/article/details/65494239 关于静态库和动态库的使用和制作方法. http://blog.csdn. ...
- C语言之函数指针、回调函数的使用
一.背景 首先看下如下代码,这个定义是放在头文件的,在程序中tCdrvCallbackFkt也定义了另一个变量,而且括号后面还跟定义了几个变量,不理解这个定义. typedef void (PUBLI ...
- C 函数指针、回调函数
参考链接:https://www.runoob.com/cprogramming/c-fun-pointer-callback.html 函数指针 函数指针就是执行函数的指针,他可以像正常函数一样去调 ...
- c中函数指针和回调函数
函数指针: 指向函数的指针.(定义的函数会分配一块内存,同变量一样存在首地址)示例如下: int Func(int x); /*声明一个函数*/ int (*p) (int x); /*定义一个函数指 ...
- C 函数指针与回调函数
函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调用函数.传递参数. 函数指针变量的声明: #inclu ...
- 声明函数指针、回调函数、函数对象------c++程序设计基础、编程抽象与算法策略
声明函数指针 #include<iostream> using namespace std; double a(double aa) { return aa; } int main() { ...
- 【不在混淆的C】指针函数、函数指针、回调函数
一.指针函数 函数的返回值是指针类型. int* fun(int a,int b); 指针函数使用: 返回字符串 这里要注意,"1234567890abc"是字符串常量,*p指向的 ...
- C:函数指针、回调函数
函数指针 是一个指针,指向函数的指针,指针存放的都是地址,所以函数指针存放的是函数的地址.数组名就是数组的首地址,函数名就是函数的首地址.与数组类似. 代码demo int (*p) (int ,in ...
随机推荐
- Eclipse MyBatis generator 1.3.7插件的核心包(中文注释)
一.最近刚搭建一个项目框架,使用springboot + mybatis,但是在使用Eclipse开发时发现开发mybatis的Dao.mapper.xml和entity时特别不方便,手工去写肯定是不 ...
- Socket.EndReceive 方法 (IAsyncResult)
.NET Framework (current version) 其他版本 .NET Framework 4 .NET Framework 3.5 .NET Framework 3.0 . ...
- vim 正则表达式获取双引号中的字符
vim 正则表达式获取双引号中的字符 1.获取双引号中的字符 :%s/.*\".∗\".*/\1/ 2.用字符串建立标签 如 hello <hello></ ...
- python基于SMTP发送邮件
import smtplib from email.header import Header from email.mime.text import MIMEText ''' SMTP是发送邮件的协议 ...
- jsp 引入js、css修改后有缓存不及时更新
解决:(增加随机版本号) <link rel="stylesheet" type="text/css" href="css/1.css?v=&l ...
- Idea安装Mevn
1.下载mevn安装包. 下载地址:http://maven.apache.org/ 点击Download 2.下面这两个选哪个都可以,取决于你用什么方式解压 3.把下载好的安装包解压到一个没有中文的 ...
- Python3基础笔记_元组
# Python3 元组 ''' Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运 ...
- php中Cookies
PHP Cookies cookie 是一种在远程浏览器端储存数据并以此来跟踪和识别用户的机制,PHP 透明地支持 HTTP cookie. cookie 常用于识别用户. Cookie 是什么? c ...
- PAT甲级——A1068 Find More Coins
Eva loves to collect coins from all over the universe, including some other planets like Mars. One d ...
- sip会话流程以及sip介绍(2)
下面我们通过一个简单的场景例子来简单介绍一下 SIP 会话流程. Tom 和 Jerry 是非常好的伙伴,Tom 在他的 PC 上使用一个 SIP 的应用程序呼叫 Internet 上另一个 SIP ...