zoukankan      html  css  js  c++  java
  • 26 函数与指针分析

    1 函数类型

    • C 语言中的函数有自己特定的类型

    • 函数的类型由返回值,参数类型和参数个数共同决定

      如:int add(int i,int j) 的类型为 int(int,int)

    • C 语言中通过 typedef 为函数类型重命名typedef type name(parameter list)

      如:typedef int f(int,int);typedef void p(int);

    2 函数指针

    • 可以通过函数类型定义函数指针

      • 函数指针用于指向一个函数
      • 函数名是执行函数体的入口地址(类似于数组名代表数组首元素的地址)
      • 语法:FuncType* pointer;
    • 也可以直接定义:type(*pointer)(parameter list);

      • pointer函数指针变量名
      • type :所指函数的返回值类型
      • parameter list :所指函数的参数类型列表
    • 示例:函数指针的使用

      • Demo

        #include <stdio.h>
        
        typedef int(FUNC)(int);
        
        int test(int i)
        {
            return i * i;
        }
        
        void f()
        {
            printf("Call f()...
        ");
        }
        
        int main()
        {
            FUNC* pt = test;  //通过函数类型定义函数指针,并用test函数名进行初始化(函数名代表函数体的入口地址)
            void(*pf)() = &f;  //直接定义函数指针,并用函数f的地址初始化(&f也是函数体的入口地址,与f相同)
            
            printf("pf = %p
        ", pf);
            printf("f = %p
        ", f);
            printf("&f = %p
        ", &f);
            
            pf();//调用函数
            
            (*pf)();//调用函数
            
            printf("Function pointer call: %d
        ", pt(2));
            
            return 0;
        }
        
      • 编译运行

        pf = 0x8048400
        f = 0x8048400
        &f = 0x8048400
        Call f() ...
        Call f() ...
        Function pointer call : 4
        
    • 问题:如何使用 C 语言直接跳转某个固定的地址开始执行?

      • 利用函数指针,如对于上面的代码修改为: void(*pf)() = 0x8048400; ,直接利用函数指针跳转到地址 0x8048400 执行,而这个地址恰好是函数 f 的地址

    3 回调函数

    • 回调函数是利用函数指针实现的一种调用机制

    • 回调机制原理

      • 调用者不知道具体事件发生时需要调用的具体函数
      • 被调函数不知道何时被调用,只知道需要完成的任务
      • 当具体事件发生时,调用者通过函数指针调用具体函数
    • 回调机制中的调用者和被调用者互不依赖 ---> 监听者模式

    • 示例:回调函数使用

      • Demo

        #include <stdio.h>
        
        typedef int(*Weapon)(int);
        
        //对于fight函数,只知道使用某种武器进行攻击,而不知道是何种武器
        void fight(Weapon wp, int arg)
        {
            int result = 0;
            
            printf("Fight boss!
        ");
            
            result = wp(arg);
            
            printf("Boss loss: %d
        ", result);
        }
        
        //对于具体的武器的函数来说,并不知道什么时候会被调用
        int knife(int n)
        {
            int ret = 0;
            int i = 0;
            
            for(i=0; i<n; i++)
            {
                printf("Knife attack: %d
        ", 1);
                ret++;
            }
            
            return ret;
        }
        
        int sword(int n)
        {
            int ret = 0;
            int i = 0;
            
            for(i=0; i<n; i++)
            {
                printf("Sword attack: %d
        ", 5);
                ret += 5;
            }
            
            return ret;
        }
        
        int gun(int n)
        {
            int ret = 0;
            int i = 0;
            
            for(i=0; i<n; i++)
            {
                printf("Gun attack: %d
        ", 10);
                ret += 10;
            }
            
            return ret;
        }
        
        int main()
        {
            //在main函数中,通过函数指针连接fight函数与knife,sword,gun函数,实现回调
            fight(knife, 3);
            fight(sword, 4);
            fight(gun, 5);
            
            return 0;
        }
        
      • 编译运行

        Fight boss!
        Knife attack: 1
        Knife attack: 1
        Knife attack: 1
        Boss loss : 3
        
        Fight boss!
        Sword attack: 5
        Sword attack: 5
        Sword attack: 5
        Sword attack: 5
        Boss loss : 20
        
        Fight boss!
        Gun attack: 10
        Gun attack: 10
        Gun attack: 10
        Gun attack: 10
        Gun attack: 10
        Boss loss : 50
        
  • 相关阅读:
    淘宝破裤子奇遇记--记酷锐哲型旗舰店
    第9章 在实践中使用模板:9.5 后记
    第9章 在实践中使用模板:9.4 破译大篇幅错误信息
    第9章 在实践中使用模板:9.3 预编译头文件
    第9章 在实践中使用模板:9.2 模板和内联
    第9章 在实践中使用模板:9.1 包含模型
    第8章 编译期编程:8.5 编译期if
    第8章 编译期编程:8.4 SFINAE(替换失败并不是错误)
    第8章 编译期编程:8.3 偏特化的执行路径选择
    第8章 编译期编程:8.2 使用constexpr计算
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13773683.html
Copyright © 2011-2022 走看看