指针(六)
今天继续对指针进行探讨,请看下面:
函数指针:
![](http://images0.cnblogs.com/blog/324374/201312/17211931-6e180185d7e44a46a8557762492a5593.png)
下面通过一个程序,简单明了的对函数指针有个基本认识:
#include <stdio.h> void test(int n) { printf("test %d ...\n", n); } int main(void) { void (*f)(int); // 这里的f就是函数指针变量 void (*f2)(int); // 这里的f就是函数指针变量 // 以下两种写法是等价的 f = &test; f2 = test; // 以下两种写法也是等价的 f(100); // 调用函数 (*f2)(200); // 调用函数 return 0; }
运行:
需要特别说明的是:
void (*f)(int);代表的是函数指针变量,但是
void* f(int);则代表的含义就完全不一样了,由于()运算符的优先级比*要高,所以f(int)代表一个函数,void*代表函数的返回值。
下面再通过几个小例子,来进一步加深对函数指针的认识:
示例1:
![](http://images0.cnblogs.com/blog/324374/201312/17212923-614af1bdeb804414917f757c5c1897ad.png)
运行结果:
![](http://images0.cnblogs.com/blog/324374/201312/17213008-86e0d0908618455f85bdae55b5dc7a9b.png)
如果不用函数指针,也不可能用一个函数可以包含多个函数的功能,从代码复用的角度来说,用它也是非常好的体现。
示例2【它有一个很重要的意义,需好好理解】:
这个示例主要是用到系统函数,对结构体数组元素进行排序,这个函数为qsort,通过man帮助查看一下:
![](http://images0.cnblogs.com/blog/324374/201312/17215701-cc05a0c7978548cab8beaa50b5157b50.png)
具体代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct month { int number; char* name; } month_t; //第一种排序规则是以名字升序进行排序 int comp1(const void* m1, const void* m2) { month_t* mi1 = (month_t*)m1; month_t* mi2 = (month_t*)m2; return strcmp(mi1->name, mi2->name); } //第二种排序规则是以数字降序进行排序 int comp2(const void* m1, const void* m2) { month_t* mi1 = (month_t*)m1; month_t* mi2 = (month_t*)m2; return mi2->number - mi1->number; } //输出结构体的元素内容 void output(month_t* months, int number) { int i; for (i=0; i<number; i++) { printf("%d %s\n", months[i].number, months[i].name); } } int main(void) { month_t months[] = { { 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" }, { 5, "may" }, { 6, "jun" }, { 7, "jul" }, { 8, "aug" }, { 9, "sep" }, {10, "oct" }, {11, "nov" }, {12, "dec" } }; //算出结构体的个数 int number_of_months = sizeof(months) / sizeof(month_t); qsort(months, number_of_months, sizeof(month_t), comp1);//排序规则跟java中的排序一样,类似于方法回调 output(months, number_of_months); putchar('\n'); qsort(months, number_of_months, sizeof(month_t), comp2); output(months, number_of_months); return 0; }
运行:
分析:
![](http://images0.cnblogs.com/blog/324374/201312/17221401-36d30961f9e145ed975582bfd0cd5a68.png)
![](http://images0.cnblogs.com/blog/324374/201312/17221517-d354e6f59229417993a6cd766eea7d5d.png)
通过函数指针,可以让我们的代码更加通用,是实现通用编程的一种很重要的手段。
typedef用法:
typedef为一种类型引入新的名字,类似于宏替换,但是存在差别,请看下面:
![](http://images0.cnblogs.com/blog/324374/201312/17222651-8dc04e923113411bbac2794bf59e4f4b.png)
![](http://images0.cnblogs.com/blog/324374/201312/17222920-5568a82b5f7a4e65a7bf21bb35a6d840.png)
下面,以一个实际的函数例子,这些例子在linux系统编程中会大量用到,在此正好理解它们,它就是signal:
void (*signal(int signum, void (*handler)(int)))(int);
下面一一剖析来理解上面的这种函数的定义:
![](http://images0.cnblogs.com/blog/324374/201312/18211831-19f39de74846473982dd7f9364ec18fd.png)
上面的这种写法,很难理解,这时,就可以用typedef来让程序的可读性增强:
typedef void (*sighandler_t)(int);//这时sighandler_t就不是函数指针变量了,而是函数指针类型
sighandler_t signal(int signum, sighandler_t handler);//这时,signal的第二个参数就可用函数指针类型代替,由于signal的返回值也是个函数指针,这样一来,就明了多了;
通过man来查看一下这个系统函数的声明,具体用法先不用知道,后面再学,先看下函数原形声明:
![](http://images0.cnblogs.com/blog/324374/201312/17230338-904a9e79d4f14befaa43cf91a8fd4324.png)
指针数据类型小结:
![](http://images0.cnblogs.com/blog/324374/201312/17224752-7a703df84f744fa890b4b181c8d45e9b.png)
下面最后理解一下这个复杂的表达式:
![](http://images0.cnblogs.com/blog/324374/201312/17225456-aaec49c7bb7a4ed28a431247c47854e7.png)
好了,先学到这,今天学的函数指针形态有些难懂,需好好体现,下次见!!