C++面试基础系列-函数指针与指针函数

2024-08-25 00:36

本文主要是介绍C++面试基础系列-函数指针与指针函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

系列文章目录


文章目录

  • 系列文章目录
  • C++面试基础系列-函数指针与指针函数
    • Overview
    • 1.function_pointer函数指针
    • 2.pointer_function指针函数
    • 3.面试中,最喜欢的是函数指针和指针函数的区别
      • 3.1.定义
      • 3.2.用法
      • 3.3.存储方式
    • 4.函数指针用法
    • 5.指针函数
      • 5.1.动态内存分配
      • 5.2.返回复杂数据结构的指针
      • 5.3.作为函数参数传递
    • 关于作者


C++面试基础系列-函数指针与指针函数

Overview

1.function_pointer函数指针

  • function_pointer函数指针也是一个指针,
    • 只不过函数指针可以指向函数,可以通过该指针调用函数
    • 联想到重载,多态,模板,只不过函数指针需要重新调整指针指向的函数类型

2.pointer_function指针函数

  • 指针函数实际上只是函数返回值返回一个指针

3.面试中,最喜欢的是函数指针和指针函数的区别

函数指针和指针函数是两个不同的概念,主要区别如下:

3.1.定义

  1. 指针函数:
    • 本质是一个函数,其返回值是一个指针。
    • 例如:int* fun() { /* 函数体 */ },这里的函数 fun就是一个指针函数,它返回一个指向整数的指针。
  2. 函数指针:
    • 是指向函数的指针变量。
    • 例如:int (*pf)();,这里 pf是一个函数指针,它指向一个返回值为整数的函数。

3.2.用法

  1. 指针函数的用法:

    • 先调用指针函数,得到一个指针结果,然后通过这个指针访问其所指向的内存空间中的数据。

    • 例如:

    • 看出下面代码的错误了吗?

      int* fun() {int a = 10;return &a;
      }
      int main() {int* ptr = fun();printf("%d\n", *ptr);//errorreturn 0;
      }
      
    • ERROR:a是一个局部变量,调用指向a的指针,会出现内存泄漏,应避免这种用法。

  2. 函数指针的用法:

    • 可以将函数指针作为参数传递给其他函数,实现回调函数的功能。

    • 例如:

      void callback(int (*func)(int), int arg) {int result = func(arg);printf("Result: %d\n", result);
      }
      int square(int num) {return num * num;
      }
      int main() {callback(square, 5);return 0;
      }
      

3.3.存储方式

  1. 指针函数:在内存中与普通函数一样,有特定的代码段存储函数体,执行时将在该代码段中运行。返回的指针则存储在相应的内存地址中。
  2. 函数指针:本身作为一个变量存储在内存中,它的值是所指向函数的入口地址。

4.函数指针用法

函数指针是C++中一种重要的特性,它允许将函数作为值来处理。以下是函数指针的一些常见用法:

  1. 动态函数调用
    使用函数指针可以在运行时决定调用哪个函数。这在实现回调机制、策略模式或事件处理系统时非常有用。

    void function1() { std::cout << "Function 1" << std::endl; }
    void function2() { std::cout << "Function 2" << std::endl; }
    void (*functionPtr)() = function1; // 函数指针指向function1
    functionPtr(); // 调用function1
    functionPtr = function2; // 现在指向function2
    functionPtr(); // 调用function2
    
  2. 实现回调函数
    函数指针经常用于回调函数,即作为参数传递给另一个函数,然后在该函数内部调用。

    void callback(void (*func)()) {func();
    }
    void myFunction() {std::cout << "Hello from myFunction" << std::endl;
    }
    int main() {callback(myFunction);
    }
    
  3. 作为数据成员
    在类中使用函数指针作为数据成员,允许对象根据行为的不同来调用不同的函数。

    class Event {
    public:void (*handler)(); // 函数指针作为数据成员
    };
    Event event;
    event.handler = myFunction;
    event.handler(); // 调用myFunction
    
  4. 数组和向量
    函数指针可以存储在数组或向量中,用于管理一组函数。

    void (*functions[])() = {function1, function2};
    for (auto func : functions) {func();
    }
    
  5. 函数指针类型转换
    在某些情况下,可能需要将一个函数指针转换为另一个类型的指针,或者反之。

    typedef void (*FuncType)();
    int (*intFunc)(int) = static_cast<int (*)(int)>(function1); // 类型转换
    
  6. 实现多态
    函数指针可以用来实现类似多态的行为,尤其是在使用函数作为类的成员或参数时。

    class Base {
    public:virtual void execute() = 0;
    };
    class Derived : public Base {
    public:void execute() override {std::cout << "Execute in Derived" << std::endl;}
    };
    Base* basePtr = new Derived();
    (*basePtr).execute(); // 多态调用
    delete basePtr;
    
  7. 用于排序和搜索算法
    在标准库算法中,如 std::sortstd::find_if,可以传递函数指针或函数对象来指定自定义的比较或谓词函数。

    int array[] = {5, 3, 2, 4, 1};
    std::sort(std::begin(array), std::end(array),[](int a, int b) { return a > b; }); // lambda表达式作为函数指针使用
    
  8. 信号处理
    在Unix和类Unix系统中,signal函数允许为各种信号注册信号处理函数,这通常通过函数指针完成。

    void signalHandler(int signal) {std::cout << "Signal received" << std::endl;
    }
    // 注册信号处理函数
    signal(SIGINT, signalHandler);
    
  9. 函数指针的指针
    可以创建函数指针的数组或指针,这在实现函数表或多级回调时很有用。

    void (*functionTable[])() = {function1, function2};
    void (**functionTablePtr)() = functionTable;
    (*functionTablePtr)[0](); // 调用function1
    
  10. 与C ABI兼容
    由于C++兼容C的ABI(应用程序二进制接口),函数指针在C和C++之间可以互用,这在编写跨语言的库或接口时非常有用。

函数指针是C++中实现多态、回调和高阶函数(即接受或返回函数的函数)的关键工具。然而,过度使用函数指针可能会使代码难以理解和维护,因此应谨慎使用,并考虑使用更现代的C++特性,如函数对象、lambda表达式和std::function。

5.指针函数

指针函数是一种返回指针类型的函数。以下是指针函数的一些用法:

5.1.动态内存分配

在 C 和 C++中,可以使用指针函数来动态分配内存并返回指向该内存的指针。例如:

int* allocateArray(int size) {int* arr = new int[size];return arr;
}

在这个例子中,allocateArray函数接受一个整数参数size,用于指定要分配的数组大小。函数内部使用new关键字动态分配一个整数数组,并返回指向该数组的指针。使用时可以这样调用:

int main() {int* myArray = allocateArray(10);// 使用 myArraydelete[] myArray;return 0;
}

5.2.返回复杂数据结构的指针

当需要从函数中返回一个复杂的数据结构时,可以使用指针函数。例如,假设有一个结构体表示学生信息:

struct Student {std::string name;int age;
};Student* createStudent(std::string name, int age) {Student* s = new Student;s->name = name;s->age = age;return s;
}

使用方式如下:

int main() {Student* student = createStudent("Tom", 18);// 使用 studentdelete student;return 0;
}

5.3.作为函数参数传递

指针函数的返回值可以作为其他函数的参数进行传递。例如:

void processArray(int* arr, int size) {for (int i = 0; i < size; i++) {arr[i] *= 2;}
}int* generateArray(int size) {int* arr = new int[size];for (int i = 0; i < size; i++) {arr[i] = i + 1;}return arr;
}

可以这样调用:

int main() {int* myArray = generateArray(5);processArray(myArray, 5);// 使用 myArraydelete[] myArray;return 0;
}

在这个例子中,generateArray函数生成一个整数数组,然后将其作为参数传递给processArray函数进行处理。


关于作者

  • 微信公众号:WeSiGJ
  • GitHub:https://github.com/wesigj/cplusplusboys
  • CSDN:https://blog.csdn.net/wesigj
  • 微博:
  • -版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

这篇关于C++面试基础系列-函数指针与指针函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104052

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

MySQL中my.ini文件的基础配置和优化配置方式

《MySQL中my.ini文件的基础配置和优化配置方式》文章讨论了数据库异步同步的优化思路,包括三个主要方面:幂等性、时序和延迟,作者还分享了MySQL配置文件的优化经验,并鼓励读者提供支持... 目录mysql my.ini文件的配置和优化配置优化思路MySQL配置文件优化总结MySQL my.ini文件

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数