彻底搞定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语言函数指针和回调函数的更多相关文章

  1. VC++的函数指针和回调函数 及友元函数

    什么是函数指针 函数指针是指向函数的指针变量.也就是说,它是一个指针变量,而且该指针指向一个函数. 对于指针变量来说,它的值是它指向的变量的地址.举个例子:指针变量pi是指向一个整型变量i的指针,则变 ...

  2. 深入浅出剖析C语言函数指针与回调函数(一)【转】

    本文转载自:http://blog.csdn.net/morixinguan/article/details/65494239 关于静态库和动态库的使用和制作方法. http://blog.csdn. ...

  3. C语言之函数指针、回调函数的使用

    一.背景 首先看下如下代码,这个定义是放在头文件的,在程序中tCdrvCallbackFkt也定义了另一个变量,而且括号后面还跟定义了几个变量,不理解这个定义. typedef void (PUBLI ...

  4. C 函数指针、回调函数

    参考链接:https://www.runoob.com/cprogramming/c-fun-pointer-callback.html 函数指针 函数指针就是执行函数的指针,他可以像正常函数一样去调 ...

  5. c中函数指针和回调函数

    函数指针: 指向函数的指针.(定义的函数会分配一块内存,同变量一样存在首地址)示例如下: int Func(int x); /*声明一个函数*/ int (*p) (int x); /*定义一个函数指 ...

  6. C 函数指针与回调函数

    函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调用函数.传递参数. 函数指针变量的声明: #inclu ...

  7. 声明函数指针、回调函数、函数对象------c++程序设计基础、编程抽象与算法策略

    声明函数指针 #include<iostream> using namespace std; double a(double aa) { return aa; } int main() { ...

  8. 【不在混淆的C】指针函数、函数指针、回调函数

    一.指针函数 函数的返回值是指针类型. int* fun(int a,int b); 指针函数使用: 返回字符串 这里要注意,"1234567890abc"是字符串常量,*p指向的 ...

  9. C:函数指针、回调函数

    函数指针 是一个指针,指向函数的指针,指针存放的都是地址,所以函数指针存放的是函数的地址.数组名就是数组的首地址,函数名就是函数的首地址.与数组类似. 代码demo int (*p) (int ,in ...

随机推荐

  1. 【转载】浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在 ...

  2. dos中文显示乱码怎么办?

    其实只需要一条命令 chcp 65001 执行该操作后,代码页就被变成UTF-8了 也可是GBK,  命令式:  chcp  936 2.修改窗口属性,改变字体 在命令行标题栏上点击右键,选择&quo ...

  3. VS开发工具的常用插件

    转 http://www.spersky.com/post/vsPlugins.html 我目前主要用的是Hide Main Page——公司配给的电脑屏幕分辨率好小,还是1366*768的,去掉头可 ...

  4. 精度试验结果报告Sleep, GetTickCount, timeGetTime, QueryPerformanceCounter

    一段简单的代码来实现精度试验 int main() {       // 初始化代码       ......       int i = 0;       while(i++ < 1000) ...

  5. .NETFramework-Web.Mvc:HttpXxxAttribute-目录

    ylbtech-.NETFramework-Web.Mvc:HttpXxxAttribute-目录 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返 ...

  6. 13-2-return

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Caffe系列2——Windows10制作LMDB数据详细过程(手把手教你制作LMDB)

    Windows10制作LMDB详细教程 原创不易,转载请注明出处:https://www.cnblogs.com/xiaoboge/p/10678658.html 摘要: 当我们在使用Caffe做深度 ...

  8. [JZOJ3293] 【SHTSC2013】阶乘字符串

    题目 题目大意 给你一个字符串,判断这个字符串是否为"阶乘字符串". 就是子序列包含字符集的全排列的字符串. n≤26n\leq 26n≤26 ∣S∣≤450|S|\leq 450 ...

  9. maven/gradle版本统一示例

    <dependencyManagement> <dependencies> <dependency> <groupId>org.springframew ...

  10. csps模拟测试7273简单的操作小P的2048小P的单调数列小P的生成树

    题面:https://www.cnblogs.com/Juve/articles/11678564.html 简单的操作: 考场上sb了,没看出来 如果有奇环一定不能缩成一条链,判掉奇环后就是bfs最 ...