免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 58822 | 回复: 80
打印 上一主题 下一主题

[函数] 关于指针与函数的几点小结 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-09-19 16:14 |只看该作者 |倒序浏览
本帖最后由 JohnBull 于 2011-05-08 21:26 编辑

心血来潮, 想对函数指针的几个用法小结一下, 都是平常容易见到的, 如果还有其它不觉的用法也请朋友们不吝赐教.

若有错误之处,还请指正.

1. 首先,在C语言中函数是一种function-to-pointer的方式,即对于一个函数,会将其自动转换成指针的类型.如:

  1. #include<stdio.h>

  2. void fun()
  3. {
  4. }

  5. int main()
  6. {
  7.         printf("%p      %p      %p\n", &fun, fun, *fun);
  8.         return 0;
  9. }
复制代码
这三个值的结果是一样的. 其实对于最后的那个*fun, 即使前面加上很多个*号, 其结果也不变, 即**fun, ***fun的结果都是一样的. 对于这个问题, 因为之前讲过函数是一种
function-to-pointer方式, 其会自动转换成指针的类型, &fun是该函数的地址, 为指针类型, fun是一个函数, 会转换成其指针类型, 而对于*fun, 由于fun已经变成了指针类型, 指向这个函数, 所以*fun就是取这个地址的函数, 而又根据function-to-pointer, 该函数也转变成了一个指针, 所以以此类推, 这三个值的结果是相同的.

2. 如何调用一个地址上的函数
  如果知道了一个函数所在的地址, 可以将其强制转化成某一种类型的函数指针, 然后再根据这个指针去调用这个地址的函数. 如:

  1. #include<stdio.h>

  2. void f(int i)
  3. {
  4.         printf("i = %d\n", i);
  5. }

  6. int main()
  7. {
  8.         unsigned long add;
  9.         add = (unsigned long)f;
  10.         ((void (*)(int))add)(10);
  11.         (*(void (*)(int))add)(20);
  12.         return 0;
  13. }
复制代码
使用(void (*)(int))的方式可以将一个地址转换成一个带int参数且没有返回值的函数的指针类型, 然后再去调用, 由于第1点中讲的function-to-pointer, 所以最后两条语句中加与不加那个*号效果都是一样的. 在嵌入式方面经常用到这种方式.

3. 函数指针数组的用法.
有时候需要定义一个数组, 其内容为一系列的函数指针, 然后对其进行调用, 如:

  1. #include<stdio.h>
  2. int max(int v1, int v2)
  3. {
  4.         return (v1 > v2 ? v1 : v2);
  5. }

  6. int min(int v1, int v2)
  7. {
  8.         return (v1 < v2 ? v1 : v2);
  9. }

  10. int sum(int v1, int v2)
  11. {
  12.         return (v1 + v2);
  13. }

  14. int main()
  15. {
  16.         int (*p[3])(int, int);
  17.         p[0] = max;
  18.         p[1] = min;
  19.         p[2] = sum;

  20.         printf("p[0] = %d\n", (p[0])(3, 5));
  21.         printf("p[1] = %d\n", (p[1])(4, 6));
  22.         printf("p[2] = %d\n", (p[2])(1, 2));
  23.         return 0;
  24. }
复制代码
虽然感觉这种方法有点累赘, 但是也算是一种使用的方式, 所以介绍一下.

4.返回一个指向数组的指针的方式
可以让函数返回一个指向数组的一个指针, 如:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. int (*p())[10]
  4. {
  5.         int (*m)[10];
  6.         int i;
  7.         m = (int (*)[10])malloc(10 * sizeof(int));
  8.         if (m == NULL)
  9.         {
  10.                 printf("malloc error\n");
  11.                 exit(1);
  12.         }
  13.         for (i = 0; i < 10; i++)
  14.                 *(*m+i) = i+1;
  15.         return m;
  16. }

  17. int main()
  18. {
  19.         int (*a)[10];
  20.         int i;
  21.         a = p();
  22.         for (i = 0; i < 10; i++)
  23.                 printf("%d ", *(*a+i));
  24.         printf("\ndone\n");
  25.         return 0;
  26. }
复制代码
这种方式中,int (*a)[10]是一个指向一维数组的一个指针, 而p()也是返回一个指向一维数组的一个指针.

5.返回一个函数指针的指针
对这个问题, signal()函数是最好的例子,

  1. void (*signal (int signo, void (*func)(int)))(int);
复制代码
很多朋友刚开始看这个函数定义的时候是不太懂, 其实可以一步一步地慢慢看, 我以前是这样分析的, 希望能对大家有用.
int (*p)();
这是一个函数指针, p所指向的函数是一个不带任何参数, 并且返回值为int的一个函数.
int (*fun())();
这个式子与上面式子的区别在于用fun()代替了p,而fun()是一个函数,所以说就可以看成是fun()这个函数执行之后,它的返回值是一个函数指针,这个函数指针(其实就是上面的p)所指向的函数是一个不带任何参数,并且返回值为int的一个函数.所以说对于

  1. void (*signal(int signo, void (*fun)(int)))(int);
复制代码
就可以看成是signal()函数(它自己是带两个参数,一个为整型,一个为函数指针的函数), 而这个signal()函数的返回值也为一个函数指针,这个函数指针指向一个带一个整型参数,并且返回值为void的一个函数.
signal函数返回的其实是指向以前的信号处理程序的指针, 所以举一个例子来说明返回指向函数的指针的用法,如:

  1. #include<signal.h>
  2. #include<stdlib.h>
  3. #include<stdio.h>

  4. void sig_fun2(int signo)
  5. {
  6.         printf("in sig_fun2:%d\n", signo);
  7. }

  8. void sig_fun1(int signo)
  9. {
  10.         printf("in sig_fun1:%d\n", signo);
  11. }

  12. int main()
  13. {
  14.         unsigned long i;
  15.         if (signal(SIGUSR1, sig_fun1) == SIG_ERR)
  16.         {
  17.                 printf("signal fun1 error\n");
  18.                 exit(1);
  19.         }

  20.         (signal(SIGUSR1, sig_fun2))(30);

  21.         printf("done\n");
  22.         return 0;
  23. }
复制代码
6. 使用函数指针作为参数的情况
在函数的参数中, 可能会带有一个函数指针, 这在signal()函数中是出现了的, 另外再写个例子如:

  1. #include<stdio.h>

  2. int max(int v1, int v2)
  3. {
  4.         return (v1 > v2 ? v1 : v2);
  5. }

  6. int min(int v1, int v2)
  7. {
  8.         return (v1 < v2 ? v1 : v2);
  9. }

  10. int sum(int v1, int v2)
  11. {
  12.         return (v1 + v2);
  13. }

  14. int fun(int a, int b, int (*call)(int, int))
  15. {
  16.         return (call(a, b));
  17. }

  18. int main()
  19. {
  20.         printf("max=%d\n", fun(1, 2, max));
  21.         printf("min=%d\n", fun(3, 4, min));
  22.         printf("sum=%d\n", fun(5, 6, sum));
  23.         return 0;
  24. }
复制代码
其实在很多排序函数中就是使用的这个参数为函数指针的方式来进行调用的.

草草地总结了一下, 希望能有一些用.  

论坛徽章:
0
2 [报告]
发表于 2007-09-19 16:21 |只看该作者
原帖由 scutan 于 2007-9-19 16:14 发表
心血来潮, 想对函数指针的几个用法小结一下, 都是平常容易见到的, 如果还有其它不觉的用法也请朋友们不吝赐教.

若有错误之处,还请指正.

1. 首先,在C语言中函数是一种function-to-pointer的方式,即对于一个 ...

赞lz的热心。
对于函数指针数组,其实这是很常用的。一个常见的例子就是linux下的syscall table了。虽然是用汇编写的,但实质是一样的

论坛徽章:
0
3 [报告]
发表于 2007-09-19 16:27 |只看该作者
原帖由 zx_wing 于 2007-9-19 16:21 发表

赞lz的热心。
对于函数指针数组,其实这是很常用的。一个常见的例子就是linux下的syscall table了。虽然是用汇编写的,但实质是一样的


嗯. 我写的时候倒把这点给忘了, 通过系统调用号来找到其函数入口地址. 谢谢提醒.

论坛徽章:
0
4 [报告]
发表于 2007-09-19 16:30 |只看该作者
不错,赞一个

论坛徽章:
0
5 [报告]
发表于 2007-09-19 17:00 |只看该作者
scutan的热心值得肯定 ,可是你的blog咋就没更新上呢。。

论坛徽章:
0
6 [报告]
发表于 2007-09-19 17:00 |只看该作者
楼主可不可以再这样介绍下:
1. 用 typedef 定义一个函数指针类型
2. 把这个类型的变量当成普通的变量使用
    既然是普通变量,什么数组啊,返回值啊,都不需要讨论了。

论坛徽章:
0
7 [报告]
发表于 2007-09-19 17:04 |只看该作者
原帖由 ruoyisiyu 于 2007-9-19 17:00 发表
scutan的热心值得肯定 ,可是你的blog咋就没更新上呢。。


呵呵, 刚刚才写好.

论坛徽章:
0
8 [报告]
发表于 2007-09-19 17:27 |只看该作者
可以将 ((void (*)(int))add)(10) 转换为 :
typedef void (*FUNC_ADDR)(int);
调用 :((FUNC_ADDR)add)(10);
这样更清楚一些

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
9 [报告]
发表于 2007-09-19 17:30 |只看该作者

回复 #7 scutan 的帖子

辛苦了!!
学习了!

论坛徽章:
0
10 [报告]
发表于 2007-09-19 17:59 |只看该作者
谢谢刚才大家的提醒, 我对刚才的几个代码使用typedef作了如下的修改, 看起来简便一些.

标号与上面的标号相同.

2.

  1. #include<stdio.h>

  2. typedef void (*pfun)(int);

  3. void f(int i)
  4. {
  5.         printf("i = %d\n", i);
  6. }

  7. int main()
  8. {
  9.         unsigned long add;
  10.         add = (unsigned long)f;
  11.         ((pfun)add)(10);
  12.         (*(pfun)add)(20);
  13.         return 0;
  14. }
复制代码


3.

  1. #include<stdio.h>

  2. typedef int (*pfun)(int, int);

  3. int max(int v1, int v2)
  4. {
  5.         return (v1 > v2 ? v1 : v2);
  6. }

  7. int min(int v1, int v2)
  8. {
  9.         return (v1 < v2 ? v1 : v2);
  10. }

  11. int sum(int v1, int v2)
  12. {
  13.         return (v1 + v2);
  14. }

  15. int main()
  16. {
  17.         pfun p[3];
  18.         p[0] = max;
  19.         p[1] = min;
  20.         p[2] = sum;

  21.         printf("p[0] = %d\n", (p[0])(3, 5));
  22.         printf("p[1] = %d\n", (p[1])(4, 6));
  23.         printf("p[2] = %d\n", (p[2])(1, 2));
  24.         return 0;
  25. }
复制代码


4.

  1. #include<stdio.h>
  2. #include<stdlib.h>

  3. typedef int (*pfun)[10];

  4. pfun p()
  5. {
  6.         pfun m;
  7.         int i;
  8.         m = (pfun)malloc(10 * sizeof(int));
  9.         if (m == NULL)
  10.         {
  11.                 printf("malloc error\n");
  12.                 exit(1);
  13.         }
  14.         for (i = 0; i < 10; i++)
  15.                 *(*m+i) = i+1;
  16.         return m;
  17. }

  18. int main()
  19. {
  20.         pfun a;
  21.         int i;
  22.         a = p();
  23.         for (i = 0; i < 10; i++)
  24.                 printf("%d ", *(*a+i));
  25.         printf("\ndone\n");
  26.         return 0;
  27. }
复制代码


5.

  1. #include<stdio.h>

  2. typedef int (*pfun)(int, int);

  3. int max(int v1, int v2)
  4. {
  5.         return (v1 > v2 ? v1 : v2);
  6. }

  7. int min(int v1, int v2)
  8. {
  9.         return (v1 < v2 ? v1 : v2);
  10. }

  11. int sum(int v1, int v2)
  12. {
  13.         return (v1 + v2);
  14. }

  15. int fun(int a, int b, pfun call)
  16. {
  17.         return (call(a, b));
  18. }

  19. int main()
  20. {
  21.         printf("max=%d\n", fun(1, 2, max));
  22.         printf("min=%d\n", fun(3, 4, min));
  23.         printf("sum=%d\n", fun(5, 6, sum));
  24.         return 0;
  25. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP