【C语言进阶】C语言指针的高阶用法

相信大家当初学习c语言的时候,老师一定跟你说过这样的一句大实话:【**指针,是c语言的灵魂**】。 ​ 笔者自出来工作以来,几乎天天都要跟c语言打交道,回过头来想一想,这话确实没有错。
​ 本文,打算从一个另类的角度,介绍下c语言指针的高级用法,通过本文的阅读,你将了解到以下知识:
c语言的指针是什么? c语言指针的高级应用:函数指针 函数指针的具体应用示例 c语言的指针是什么 ​ 指针是什么?相信所有的c语言教程,都会告诉你:【指针就是地址】。没错,的确是这么回事。c语言的指针就好比房屋的地址,只要有了地址,我们就可以访问到全世界的每一个角落。c语言的世界也是如此,地址就是一切,有了地址,就没有干不成的事情。
​ 在c语言里,如果想对一个int类型的变量a进行赋值操作,我们会这样写: a = 5;这样的形式,就是直接访问。对应的,我们有间接访问的方式,就是通过指针来实现。比如我们可以定义一个指针 int *b = &a; 指针b存放的是a变量的地址,我们通过这样: *b = 5;一样可以实现对a进行赋值操作,这就是间接访问的力量。
​ c语言的指针是灵活的,它不仅可以像如上代码一样,指向一个普通变量,它也可以指向一个结构体变量,甚至还可以指向一个函数名。原因就在于,函数名,在c语言的语法里,本质上就代表了函数的执行地址,说白了,它也是一个“指针”。而这,就是我们以下要详细介绍的【函数指针】。
c语言指针的高级应用:函数指针 ​ 【函数指针】,顾名思义,就是一个指向函数的指针,它的本质还是一个指针,只不过这个指针指向的内容是一个函数。
​ 在讲解【函数指针】之前,我们先假设有若干个函数,它们的原型定义如下所示:
int test_function_1(int arg);int test_function_2(int arg);int test_function_3(int arg);...int test_function_n(int arg); [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ngxkhox2-1661923373249)(data:image/gif;base64,r0lgodlhaqabapabap///waaach5baekaaaalaaaaaabaaeaaaicraeaow==)]
​ 从函数原型上我们可以知道,这些个函数都是接收一个int类型的形参,返回值类型为int型。从原型上看,这几个函数几乎是一模一样,那么我们有没有方法可以将这些原型一致的函数重新整理定义呢?答案肯定是,有的。
​ 追求高效、简洁的c语言就我们提供了一个非常有用的关键字typedef,通过typedef我们可以重新创造出一个新的数据类型,而不再局限于c语言的基本数据类型。比如我们就可以利用typedef定义一个叫形如上述函数原型的【函数指针】数据类型,它的写法如下所示:
typedef int (*function)(int arg); [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mlekq9bo-1661923373252)(data:image/gif;base64,r0lgodlhaqabapabap///waaach5baekaaaalaaaaaabaaeaaaicraeaow==)]
​ 从定义上看,因为()拥有最高优先级,所以*function首先结合在一起,这就决定了它是一个指针。接着,*function的后面接上了(int arg),这就是函数的入参;而前面的int 就表示函数的返回值。这就是【函数指针】的原型定义。
​ 【函数指针】最为一种特殊的指针,自然它也是要指向内容才能使用的,毫无疑问,它就是要指向对应原型的函数。具体怎么使用呢?
函数指针的具体应用示例 ​ 【函数指针】这种高阶用法,可能有些人用得比较少,但是如果你阅读过类似openssl这样的大型c语言编写的开源代码之后,相信你一定会感叹:原来,c语言的指针还能这么用!!!
​ 有了【函数指针】的利器,我们就可以用它来大做文章,请看以下示例代码:
int test_function_1(int arg){ printf(this msg is printed form %s ...\n, __func__); return arg;}int test_function_2(int arg){ printf(this msg is printed form %s ...\n, __func__); return arg;}int test_function_3(int arg){ printf(this msg is printed form %s ...\n, __func__); return arg;}typedef int (*function)(int arg);int function_pointer_test_1(void){ int ret; int arg = 1; function func = null; //定义个函数指针 func = test_function_1; //把函数指针指向test-function-1 //ret = test_function_1(arg); //通过函数名直接调用test-function-1函数 ret = func(arg); //通过函数指针间接调用test-function-1函数 func = test_function_2; //把函数指针指向test-function-2 //ret = test_function_2(arg); //通过函数名直接调用test-function-2函数 ret = func(arg); //通过函数指针间接调用test-function-2函数 func = test_function_3; //把函数指针指向test-function-3 //ret = test_function_3(arg); //通过函数名直接调用test-function-3函数 ret = func(arg); //通过函数指针间接调用test-function-3函数 return 0;}int function_pointer_test_2(void){ int ret; int arg = 1; int i = 0; function func = null; //定义个函数指针 function func_array[] = //定义一组函数列表 { test_function_1, test_function_2, test_function_3, }; //终极大招,循环处理3个函数的间接调用 for (i = 0; i < sizeof(func_array); i ++) { func = func_array[i]; //把函数指针指向对应的函数 ret = func(arg); //通过函数指针间接调用对应的函数 } return 0;}int main(int argc, char **argv){ function_pointer_test_1(); function_pointer_test_2(); /* 结果输出,两个function_pointer_test函数均有同样的输出结果: this msg is printed form test_function_1 ... this msg is printed form test_function_2 ... this msg is printed form test_function_3 ... */ return 0;}/*总结:虽然通过两个调用的方式,输出结果是一致的,但是显然方式2的处理更为高效、简洁;从代码的字里行间,仿佛看到c语言的“多态”:将不同的函数名赋值给同一个函数指针变量;使用同一个函数指针发起函数调用,得到不一样的结果输出,这不就是多态吗?*/ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olznhznb-1661923373260)(data:image/gif;base64,r0lgodlhaqabapabap///waaach5baekaaaalaaaaaabaaeaaaicraeaow==)]
​ 通过如上的示例代码,c语言的【多态】你get到了吗?
​ 千万不要小瞧了上面的示例代码,如果你能熟练掌握其中的【指针精髓】,再去阅读一些业内广泛使用的c语言编写的开源项目源码,比如大名鼎鼎的openssl;相信阅读之后,你的c语言功力一定会大大地提升。
​ 不过,值得注意的是,文中的示例代码均是笔者在非编程环境下编写,属于【白板编程】,难免会出现编写错误、编译不过、或执行结果不正确的情况;还请细心的读者诚心指正,感激不尽。
延伸阅读预告:
为充实c语言的指针知识,笔者将会在后续的文章中整理大名鼎鼎的c语言巨著《c和指针》,敬请期待。


展商资讯|宝德携自强全线产品及相关解决方案亮相CITE2022
微信回应并未监控聊天记录,用户隐私泄露何时休?
将基于图形的物理综合添加到FPGA的设计中
产品多样化,技术可靠 2020 年纯电动汽车在德国市场的销量增长三倍
现代起亚电动汽车ICCU故障分析
【C语言进阶】C语言指针的高阶用法
这趟“高效节能”车没有老司机,全靠英飞凌功率技术带你飞!
池塘养殖溶解氧变化本质
北峰通信PDT手持终端机全面技术升级,融合全新功能应用
关于聚合物锂电池浆料干法混料工艺的分析
长光辰芯发布8K APS-C画幅背照式堆栈CMOS图像传感器新品,CMOS图像传感器价格竞争加剧
MOSFET驱动器介绍及功耗计算
厚膜功能电路产品详细介绍
Tracealyzer利用CortexM的ITM实现流跟踪
fireflyAIO-3399J主板U-Boot使用介绍
机器学习之特征提取 VS 特征选择
SiC MOSFET电动汽车牵引逆变器设计
华为WatchGT2正式发布 售价229欧元起
2017年的物联网安全还将面临哪些挑战?
关于STM32G0将会在今年爆发吗?