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

    函数指针前的杂谈

    • 数据
      我们知道,在计算机中,所有的东西都是用0/1来表示的,正如物理世界中的基本粒子一样,所有的一些都是由0/1来组合出来的,无论数据,结构,条件,指令,函数,图像,对象,音乐,视频,以及其他。
    • 含义/信息
      对于0,1我们知道的永远只有0,1。这两家伙放在你的面前组合成一堆,你能知道这表达的意思吗?很显然,你不可能知道。所以,有了信息。
    • 组合
      通过规定,我们将8个0/1的组合,并给他们我们人类可以明白的含义,这样,人就可以和机器通过这种规定/协议来进行交流了。
    • 更高层的信息
      机器与人之间的交流,通过abcd这样的,多少有点局限,那么如何才能将这些东西组合在一起呢?正如语言一样,由单个的字母组合成单词,由单词组合成句子,用句子组合成段落,用段落组成文章...计算机语言大概也是这样子的。
    • 封装(加密/解密)
      很多时候,人都是比较懒的,特别是程序员,当<<权利的游戏>>中龙母一次次自我介绍时,带着标志性的Flag,对于你你会怎么?抛开其他的因素,当你听到龙母这个词的时候,自然而然的会让你联想到:...出生于风暴...的龙之母。
      正如你和你的伙伴用“A”表示“ok”,那么当我想表示“A”的时候该如何表示?再定义一个“B”来表示“A”,那么“B”该如何表示?所以,用到了转义,这在字符编码的时候也有,在正则表达式中也有。
    • 数据类型
      回归正题,在C语言为强类型的语言,这个类型有什么用?在我的理解,类型其实告诉你这个数据域,也就是多大的区域算是这个数据。正如国家一样,地球只有一个,而国家的划分无非是在地球上的划分,划多少,怎么划,这个就是类型来决定的了。
      char型,就取一个byte大小的数据,int就取4个byte大小的数据。同理,其他的如结构体等。取出来的其实是一堆数据,然后进过某种规则(类型的规则)去解析
    • lvalue & rvalue
      左值右值,这点,其实也很好理解。左值,表示实实在在的CPU里面某个地址上的东西,而右值表明的是一个外部输入的东西。如果你清楚汇编,在其中有个立即数。那么这个立即数就可以理解为rvalue,你如何去改变一个立即数?那只能在输出这个参数之前,修改它了。
    • 变量
      什么事变量?我的理解,就是某一个内存上的类型大小的数据,进过规则转换后的数据,这就是变量。变量实打实的存在内存中,是有地址的。只是地址的区域存在差异。
      例如:
        int a;
    

    这一句话,实际上是记录了一个内存,而&a表示这个元素的地址,这才是CPU关心的地方,而int,是从&a地址处取得多大的值,如何去解析。

    • 数组
      一个通常的例子:
        //在数组声明中
        int a[10] = {0};
    

    以上,为数组的声明,10个元素。和int a有什么差别?后面多了一个移位运算
    为什么这样说?
    a[n],这个[],如果n是正值,那么向后偏移,如果n<0,那么向前偏移。原则上,a[-1]就是a前面的一个元素。
    int a[10]表明a的10个重复。
    这里有点问题了,为什么取a的值的时候,得到的是地址?这个后面在解释.

    • 再来谈谈指针
        //一般的,会有如下的声明并初始化
        int *a = NULL;
    

    那么a是什么?和int a又有什么区别?我的理解:为了给人看的,表明,这是这个变量是地址变量,你需要找到这个变量中所说明的地址的值。也就是经常说的,间接引用。
    很显然,不能这样子,我们需要把地址和数据区分开来,所以就有了指针与数据。
    那么:

        //这是一个数据,有一个潜在的地址信息,和一个潜在的长度信息;
        int a;
        //这是一个数据,有一个潜在的数组长度和一个潜在的地址信息和潜在的类型长度信息。
        int b[10];
        //这是一个地址信息,有一个潜在的内存地址和一个固定的大小,有权限去取得该值中的数据。
        int *a;
    

    理论上来说,你通过两种方法可以修改所有你能修改的数据:

    • 声明一个数组,通过遍历数组的前端和后端来修改
    • 声明一个指针,通过指针来修改数据。

    那么,声明是函数?

    • 函数
      了解函数,首先要了解函数的机制以及程序运行的压栈出栈操作。
      当调用函数的时候,首先将函数名压栈,然后依次是参数压栈。函数在哪里?函数入栈又是什么意思?整个函数吗
      ?还是什么其他的?
      函数名,和数组名一样,也是一个变量,一个由0,1组成的东西,也是一个地址,这个地址是函数实现所在的代码的地方,当调用函数的时候,实际上是跳转到函数地址所在的地方。
      函数实际上是一些列指令和数据的组合,详细的可以去了解“风诺依曼”结构中关于PC寄存器和函数调用的地方。
      既然,函数也是一个指针,很显然我是可以通过函数指针来调用函数的。

    • 函数指针:指向函数的指针。

    那么,我可以将这个指针存放为一个数组,直接一个循环来顺序调用所有的函数,岂不是更好?以后只需要修改相应的配置文件就可以了,何必这么折腾呢?

    • 函数指针
      同数据的指针一样,函数的指针也是有类型的,如何区分这种类型?我们知道,函数的区分,实际上有两方面:
    • 函数名
    • 参数
      那么申明一个函数指针
        int (*func)(int,int); 
    

    以上就是函数指针,是不是和如下的函数声明有点像?

        int (fun_b)(int,int); 
    

    那么,*func表示的是函数的指针,如何去初始化这个函数的指针?

        int (*func[])(int,int) = {func_1,func2,fun_3,fun_4};
        //func每一个元素是一个函数的地址
        for(int i = 0;i < 4; i++){
            printf("%d
    ",func[i](1,2));
        }
    

    和正常的函数调用是一样一样的。func[i]实际的值,实际上是一个地址,只是我们采用了间接引用*这个标号来显示的表示这是一个地址。
    当然,函数的类型必须是一样的。例如,都是返回int型,都有2个int型的参数。

  • 相关阅读:
    BZOJ 2212/BZOJ 3702
    BZOJ 4761 Cow Navigation
    BZOJ 3209 花神的数论题
    BZOJ 4760 Hoof, Paper, Scissors
    BZOJ 3620 似乎在梦中见过的样子
    BZOJ 3940 Censoring
    BZOJ 3942 Censoring
    BZOJ 3571 画框
    BZOJ 1937 最小生成树
    BZOJ 1058 报表统计
  • 原文地址:https://www.cnblogs.com/ply616/p/5607609.html
Copyright © 2011-2022 走看看