搜索
bottom↓
回复: 11

C语言入门之函数指针

[复制链接]

出0入4汤圆

发表于 2017-3-19 16:54:21 | 显示全部楼层 |阅读模式
像正常的数据指针(int *,char *等),我们可以有函数指针。 下面是一个简单的例子,显示使用函数指针的声明和函数调用。
  1. #include <stdio.h>
  2. // A normal function with an int parameter
  3. // and void return type
  4. void fun(int a)
  5. {
  6.     printf("Value of a is %d\n", a);
  7. }

  8. int main()
  9. {
  10.     // fun_ptr is a pointer to function fun()
  11.     void (*fun_ptr)(int) = &fun;

  12.     /* The above line is equivalent of following two
  13.        void (*fun_ptr)(int);
  14.        fun_ptr = &fun;
  15.     */

  16.     // Invoking fun() using fun_ptr
  17.     (*fun_ptr)(10);

  18.     return 0;
  19. }
复制代码
输出:
  1. Value of a is 10
复制代码
为什么我们需要在上面的例子中像fun_ptr这样的函数指针加一个括号?如果我们删除括号,则表达式
  1. void (*fun_ptr)(int)
复制代码
变成
  1. void * fun_ptr(int)
复制代码
它是一个返回void指针的函数的声明。 有关详细信息,请参阅以下帖子。
如何声明一个指向一个函数的指针?
以下是一些有关函数指针的有趣事实。
  • 与正常指针不同,函数指针指向代码,而不是数据。 通常,函数指针存储可执行代码的开始地址。
  • 与正常指针不同,我们不使用函数指针去分配内存。
  • 函数名也可用于获取函数地址。例如,在下面的程序中,我们已删除地址运算符'&'。我们也通过删除*改变了函数调用,程序仍然工作。
  1. #include <stdio.h>
  2. // A normal function with an int parameter
  3. // and void return type
  4. void fun(int a)
  5. {
  6.     printf("Value of a is %d\n", a);
  7. }

  8. int main()
  9. {
  10.     void (*fun_ptr)(int) = fun;  // & removed

  11.     fun_ptr(10);  // * removed

  12.     return 0;
  13. }
复制代码
输出:
  1. Value of a is 10
复制代码

  • 像普通指针一样,我们可以有一个函数指针数组。
  • 函数指针可用于switch case。例如,在下面的程序中,用户被要求在0到2之间选择做不同的任务。
  1. #include <stdio.h>
  2. void add(int a, int b)
  3. {
  4.     printf("Addition is %d\n", a+b);
  5. }
  6. void subtract(int a, int b)
  7. {
  8.     printf("Subtraction is %d\n", a-b);
  9. }
  10. void multiply(int a, int b)
  11. {
  12.     printf("Multiplication is %d\n", a*b);
  13. }

  14. int main()
  15. {
  16.     // fun_ptr_arr is an array of function pointers
  17.     void (*fun_ptr_arr[])(int, int) = {add, subtract, multiply};
  18.     unsigned int ch, a = 15, b = 10;

  19.     printf("Enter Choice: 0 for add, 1 for subtract and 2 "
  20.             "for multiply\n");
  21.     scanf("%d", &ch);

  22.     if (ch > 2) return 0;

  23.     (*fun_ptr_arr[ch])(a, b);

  24.     return 0;
  25. }
复制代码
  1. Enter Choice: 0 for add, 1 for subtract and 2 for multiply
  2. 2
  3. Multiplication is 150
复制代码
  • 像正常的数据指针一样,函数指针可以作为参数传递,也可以从函数中返回。例如,象下面的C程序,wrapper()接收到一个void fun()作为参数数
  1. // A simple C program to show function pointers as parameter
  2. #include <stdio.h>

  3. // Two simple functions
  4. void fun1() { printf("Fun1\n"); }
  5. void fun2() { printf("Fun2\n"); }

  6. // A function that receives a simple function
  7. // as parameter and calls the function
  8. void wrapper(void (*fun)())
  9. {
  10.     fun();
  11. }

  12. int main()
  13. {
  14.     wrapper(fun1);
  15.     wrapper(fun2);
  16.     return 0;
  17. }
复制代码
这一点在C中特别有用,我们可以使用函数指针来避免代码冗余。
  1. // An example for qsort and comparator
  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. // A sample comparator function that is used
  5. // for sorting an integer array in ascending order.
  6. // To sort any array for any other data type and/or
  7. // criteria, all we need to do is write more compare
  8. // functions.  And we can use the same qsort()
  9. int compare (const void * a, const void * b)
  10. {
  11.   return ( *(int*)a - *(int*)b );
  12. }

  13. int main ()
  14. {
  15.   int arr[] = {10, 5, 15, 12, 90, 80};
  16.   int n = sizeof(arr)/sizeof(arr[0]), i;

  17.   qsort (arr, n, sizeof(int), compare);

  18.   for (i=0; i<n; i++)
  19.      printf ("%d ", arr[i]);
  20.   return 0;
  21. }
复制代码
输出:
  1. 5 10 12 15 80 90
复制代码
象qsort()相似,我们可以编写自己的函数,可用于任何类型的数据,可以做不同的任务没有冗余代码
  1. #include <stdio.h>
  2. #include <stdbool.h>

  3. // A compare function that is used for searching an integer
  4. // array
  5. bool compare (const void * a, const void * b)
  6. {
  7.   return ( *(int*)a == *(int*)b );
  8. }

  9. // General purpose search() function that can be used
  10. // for searching an element *x in an array arr[] of
  11. // arr_size. Note that void pointers are used so that
  12. // the function can be called by passing a pointer of
  13. // any type.  ele_size is size of an array element
  14. int search(void *arr, int arr_size, int ele_size, void *x,
  15.            bool compare (const void * , const void *))
  16. {
  17.     // Since char takes one byte, we can use char pointer
  18.     // for any type/ To get pointer arithmetic correct,
  19.     // we need to multiply index with size of an array
  20.     // element ele_size
  21.     char *ptr = (char *)arr;

  22.     int i;
  23.     for (i=0; i<arr_size; i++)
  24.         if (compare(ptr + i*ele_size, x))
  25.            return i;

  26.     // If element not found
  27.     return -1;
  28. }

  29. int main()
  30. {
  31.     int arr[] = {2, 5, 7, 90, 70};
  32.     int n = sizeof(arr)/sizeof(arr[0]);
  33.     int x = 7;
  34.     printf ("Returned index is %d ", search(arr, n,
  35.                                sizeof(int), &x, compare));
  36.     return 0;
  37. }
复制代码
输出:
  1. Returned index is 2
复制代码

上述搜索函数可以通过编写单独的自定义compare()来用于任何数据类型。
参考:
[url=httphttp://www.cs.cmu.edu/%7Eab/15-1 ... pdfnote.youdao.com/]http://www.cs.cmu.edu/~ab/15-123S11/AnnotatedNotes/Lecture14.pdf[/url]
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-087-practical-programming-in-c-january-iap-2010/lecture-notes/MIT6_087IAP10_lec08.pdf
http://www.cs.cmu.edu/~guna/15-123S11/Lectures/Lecture14.pdf
本文由Abhay Rathi提供。

出0入0汤圆

发表于 2017-3-19 17:22:23 | 显示全部楼层
听讲了。
C中的面向对象编程的关键,就是结构和函数指针。

出0入0汤圆

发表于 2017-4-8 04:39:33 | 显示全部楼层
来听课~~~
终于看懂了~~~
谢谢楼主~~~

出0入0汤圆

发表于 2017-4-8 05:51:32 | 显示全部楼层
请教一下楼主

  1. int fun(int *a)
  2. {
  3.         return (*a)*(*a);
  4. }

  5. int main()
  6. {
  7.         int v = 20;
  8.         int *p;
  9.        
  10.         //第1种用法
  11.         fun( &v );
  12.        
  13.         //第2种用法
  14.         p = &v;
  15.         fun( p );
  16.        
  17.         //请问如果不声明任何变量的情况下,想用20的值传给fun,该如何强制转化呢?

  18.         return 0;
  19. }
复制代码


出0入0汤圆

发表于 2017-4-8 14:43:27 | 显示全部楼层
好贴,在构架数据结构的时候,我喜欢用结构和函数指针。

出0入0汤圆

发表于 2017-4-8 15:42:24 来自手机 | 显示全部楼层
zhuisuoji 发表于 2017-4-8 05:51
请教一下楼主

在函数内定义个局部变量如何?

出0入0汤圆

发表于 2017-4-8 16:18:08 | 显示全部楼层
xfdr 发表于 2017-4-8 15:42
在函数内定义个局部变量如何?

目的就是想看看如何直接强制转换~~~

出0入0汤圆

发表于 2017-4-9 18:29:55 来自手机 | 显示全部楼层
zhuisuoji 发表于 2017-4-8 05:51
请教一下楼主

函数可以多定义一个参数变量

出0入93汤圆

发表于 2017-4-9 18:49:52 | 显示全部楼层
zhuisuoji 发表于 2017-4-8 16:18
目的就是想看看如何直接强制转换~~~

常数是没有地址的,因此你的问题无解。

变通方案1:采用const常量代替常数,const本质还是变量。
变通方案2:绝对定位,直接将参数硬编码,坑自己,坑读程序的家伙们。
比如:
  1. const int XXX[]  __at(0x20000000)= {20};     // 伪代码,绝对定位
  2. fun((int*)0x20000000);    //调用
复制代码

出0入0汤圆

发表于 2017-4-9 23:50:38 | 显示全部楼层
偶尔看到这种用法,解释的不错啊

出0入0汤圆

发表于 2017-4-10 07:33:54 | 显示全部楼层
学习,谢谢!!!

出0入0汤圆

发表于 2021-8-10 14:48:24 | 显示全部楼层
学习了,非常棒
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 -- 东莞阿莫电子网站 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2023-1-29 23:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表