zoukankan      html  css  js  c++  java
  • 指向函数的指针

    Author: bakari   Date: 2012.8.8

    做好总结我觉得是把知识学扎实必不可少的实践环节。这个知识点是当初自己在学习这一块做的一些笔记,现在在知识提升的情况下将它重新整理一下以作巩固之用。

    我们知道一段代码在内存中是由地址的,一个函数在编译时会被分配给一个入口地址,这个地址就是该函数中第一条指令的地址,这就是函数的指针。当调用一个函数时出了通过函数名来调用之外,还可以通过指向该函数的指针变量来调用。切记,和一切指针变量一样,一个指向函数的指针其初值也不能为空。因为它在使用之前必须被赋予一个真实的地址。

    看下面这段代码,使用普通的函数名的方式实现函数的调用,实现矩阵法求解

     1 #include "stdio.h"
     2 #include "math.h"
     3 
     4 //intergal(x ^ 2)
     5 double func1(double a,double b)  
     6 {
     7     double sum = 0.0;
     8     double length = 0.000001;
     9     double x = a;
    10     
    11     while(x < b)
    12     {
    13         sum += x*x*length;
    14         x += length;
    15     }
    16     return sum;
    17 }
    18 
    19 int main()
    20 {
    21     double result = 0.0;
    22     result = func1(0.0,1.0);
    23     printf("%g\n",result);
    24 }

    现在改写上面的代码,使用一个指向函数的指针变量来调用函数:

     1 #include "stdio.h"
     2 #include "math.h"
     3 
     4 //intergal(x ^ 2)
     5 double func1(double a,double b)  
     6 {
     7     double sum = 0.0;
     8     double length = 0.000001;
     9     double x = a;
    10     
    11     while(x < b)
    12     {
    13         sum += x*x*length;
    14         x += length;
    15     }
    16     return sum;
    17 }
    18 
    19 int main()
    20 {
    21     double result = 0.0;
    22     double (*p)(double , double);
    23     p = func1;           //把函数的入口地址赋给p
    24     result = (*p)(0.0,1.0);
    25     printf("%g\n",result);
    26 }

    关于上面的代码,有如下几点说明:

    (1)、double(*p)()并非是指向某一个固定的函数,它仅仅表示定义这样一个类型的变量,可以将不同的函数地址赋给它。

    (2)、(*p)两侧括号不能省,p先与*结合,表面是一个指针变量,在后面的()的内容结合,表示此指针变量指向函数而非变量,如果去掉,如:double *p()表示p()的返回类型是一个指向double型变量的指针,因为()的优先级高于*,so......

    (3)p = func1; 在给p赋值是,只需要给出函数名即可,并不需要给出参数,写成这样p = func1(0.0,1.0)则是ERROR!

    (4)、在使用函数指针式,只需将(*p)替代函数名即可,但需要显示添加实参,即使函数不带参数,括号也不能省。

    (5)、数组名可以代表数组的起始地址(首元素的地址),所以函数名也可以代表函数的入口地址(函数中的首条指令的地址)。但对于指向函数的指针变量,它只能指向函数的入口处而无法指向函数中某条具体的指令,因此,对于p+n,p++等指针运算对于指向函数的指针没有意义。

    (6)、获得一个函数的地址的方法与获得一个变量的地址的方法一样,所以,p = func1;也可以写成P = &func1;但前提必须保证func1已经声明过。如:double (*p)(double , double);

    所以,通过以上的了解,我们知道了指向函数的指针的灵活性,一个指针变量可以调用多个不同的函数,这对于程序的优化和简化都起了很大的作用。

    看下面的程序,接着上面的,矩阵法求以下几个积分:

     1 #include "stdio.h"
     2 #include "math.h"
     3 
     4 //intergal(x ^ 2)
     5 double func1(double a,double b)  
     6 {
     7     double sum = 0.0;
     8     double length = 0.000001;
     9     double x = a;
    10     
    11     while(x < b)
    12     {
    13         sum += x*x*length;
    14         x += length;
    15     }
    16     return sum;
    17 }
    18 
    19 
    20 double func2(double a,double b)  //intergal( sin(x) )
    21 {
    22     double sum = 0.0;
    23     double length = 0.000001;
    24     double x = a;
    25     
    26     while(x < b)
    27     {
    28         sum += sin(x)*length;
    29         x += length;
    30     }
    31     return sum;
    32 }
    33 
    34 double func3(double a,double b)  //intergal( e ^ (x ^ -2))
    35 {
    36     double sum = 0.0;
    37     double length = 0.000001;
    38     double x = a;
    39     
    40     while(x < b)
    41     {
    42         sum += exp(sqrt(x))*length;
    43         x += length;
    44     }
    45     return sum;
    46 }
    47 
    48 void intergal (double a,double b,double (*fun) (double,double))
    49 {
    50     double result = 0.0;
    51     result = (*fun)(a,b);
    52     printf("%g\n",result);
    53 }
    54 
    55 int main()
    56 {
    57     cout<<"计算x ^ 2在0 ~ 1上的定积分结果"<<endl;
    58     intergal(0.0,1.0,func1);
    59 
    60     cout<<"计算sin (x)在0 ~ 1上的定积分结果"<<endl;
    61     intergal(0.0,3.141593,func2);
    62 
    63     cout<<"计算 e ^ (x ^ -2)在0 ~ 1上的定积分结果"<<endl;
    64     intergal(0.0,1.0,func3);
    65     return 0;
    66 }

    好了,应该对这一块有了个大概的认识了,这对于以后的学习也能起一定的帮助。


    更多干货请移步我的公众号「aCloudDeveloper」,专注技术干货分享,期待与你相遇。

    stay hungry stay foolish ----jobs 希望多多烧香!
  • 相关阅读:
    zigbee芯片
    笔记本ubuntu安装wifi驱动(未完成)
    我错了的N个学习
    《华为工作法》读书笔记
    bbblack的网络socket通信实验
    NB-IOT连接移动onenet平台流程
    移动onenet基础通信套件V1.08版本的AT指令测试
    CC3200使用MQTT的SSL加密证书可用日期修改
    利尔达NB-IOT模块烧写固件的步骤
    树莓派相机
  • 原文地址:https://www.cnblogs.com/bakari/p/2631851.html
Copyright © 2011-2022 走看看