ztrx 发表于 2017-3-19 16:54:21

C语言入门之函数指针

像正常的数据指针(int *,char *等),我们可以有函数指针。 下面是一个简单的例子,显示使用函数指针的声明和函数调用。
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
    printf("Value of a is %d\n", a);
}

int main()
{
    // fun_ptr is a pointer to function fun()
    void (*fun_ptr)(int) = &fun;

    /* The above line is equivalent of following two
       void (*fun_ptr)(int);
       fun_ptr = &fun;
    */

    // Invoking fun() using fun_ptr
    (*fun_ptr)(10);

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

int main()
{
    void (*fun_ptr)(int) = fun;// & removed

    fun_ptr(10);// * removed

    return 0;
}输出:Value of a is 10

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

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

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

    if (ch > 2) return 0;

    (*fun_ptr_arr)(a, b);

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

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

// A function that receives a simple function
// as parameter and calls the function
void wrapper(void (*fun)())
{
    fun();
}

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

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

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

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

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

// A compare function that is used for searching an integer
// array
bool compare (const void * a, const void * b)
{
return ( *(int*)a == *(int*)b );
}

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

    int i;
    for (i=0; i<arr_size; i++)
      if (compare(ptr + i*ele_size, x))
         return i;

    // If element not found
    return -1;
}

int main()
{
    int arr[] = {2, 5, 7, 90, 70};
    int n = sizeof(arr)/sizeof(arr);
    int x = 7;
    printf ("Returned index is %d ", search(arr, n,
                               sizeof(int), &x, compare));
    return 0;
}输出:Returned index is 2
上述搜索函数可以通过编写单独的自定义compare()来用于任何数据类型。
参考:
http://www.cs.cmu.edu/%7Eab/15-123S11/AnnotatedNotes/Lecture14.pdfnote.youdao.com/]http://www.cs.cmu.edu/~ab/15-123S11/AnnotatedNotes/Lecture14.pdf
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提供。

Excellence 发表于 2017-3-19 17:22:23

听讲了。
C中的面向对象编程的关键,就是结构和函数指针。

zhuisuoji 发表于 2017-4-8 04:39:33

来听课~~~
终于看懂了~~~
谢谢楼主~~~

zhuisuoji 发表于 2017-4-8 05:51:32

请教一下楼主

int fun(int *a)
{
        return (*a)*(*a);
}

int main()
{
        int v = 20;
        int *p;
       
        //第1种用法
        fun( &v );
       
        //第2种用法
        p = &v;
        fun( p );
       
        //请问如果不声明任何变量的情况下,想用20的值传给fun,该如何强制转化呢?

        return 0;
}


zqy517 发表于 2017-4-8 14:43:27

好贴,在构架数据结构的时候,我喜欢用结构和函数指针。

xfdr 发表于 2017-4-8 15:42:24

zhuisuoji 发表于 2017-4-8 05:51
请教一下楼主

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

zhuisuoji 发表于 2017-4-8 16:18:08

xfdr 发表于 2017-4-8 15:42
在函数内定义个局部变量如何?

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

Excellence 发表于 2017-4-9 18:29:55

zhuisuoji 发表于 2017-4-8 05:51
请教一下楼主

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

takashiki 发表于 2017-4-9 18:49:52

zhuisuoji 发表于 2017-4-8 16:18
目的就是想看看如何直接强制转换~~~

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

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

liuhengpeng123 发表于 2017-4-9 23:50:38

偶尔看到这种用法,解释的不错啊

dory_m 发表于 2017-4-10 07:33:54

学习,谢谢!!!

zxh1059 发表于 2021-8-10 14:48:24

学习了,非常棒
页: [1]
查看完整版本: C语言入门之函数指针