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#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程