24.指向函数的指针

24.指针-指针和函数-指向函数的指针


24.1 知识点

函数在内存中的存储

我们之前学习了变量的存储。变量是存储在内存中的小房间中的。那么函数是否存储在内存中呢?答案是肯定的,只不过它的存储区域有所不同!

当程序启动时,操作系统会将程序的各个部分(包括代码段、数据段、堆和栈)加载到内存中。在这个过程中,程序中定义的所有函数的机器码(即执行指令)会被加载到代码段中。

代码段

代码段是程序内存中的一部分,专门用于存储可执行代码。它是只读的,防止在执行过程中修改代码。而每个函数在代码段中都有一个入口地址。这个地址指向该函数的第一条指令。函数名在编译时被映射为这个地址,使得我们可以通过函数名来调用函数!

指向函数的指针

指向函数的指针(函数指针)在 C++ 中是一种强大的工具。它允许你通过指针调用函数、实现回调函数、函数数组等功能。

声明语法

返回值类型 (*指针名)(参数类型列表)

例如:

int (*function_ptr)(int, int)
void (*function_ptr)()

注意事项

  • 用函数指针指向函数时,函数的返回类型和参数类型必须和函数指针结构上完全一致。
  • 函数指针之所以需要用括号把*和指针名括起来,是为了区分函数指针和返回指针的函数。
  • 函数指针一般指向函数,而指针函数一般指返回类型是指针的函数(之后会专门讲解)。

示例代码

void test()
{
    cout << "test函数" << endl;
}

void test2(int a, int b)
{
    cout << a << endl;
    cout << b << endl;
}

声明一个函数指针,指向一个结构一样的函数:

void (*func11)() = nullptr; //test;
func11 = test;
void (*func12)() = test;

存储了相同的地址,指向test函数:

cout << test << endl;  // 00007FF6C2571230
cout << func11 << endl; // 00007FF6C2571230
cout << func12 << endl; // 00007FF6C2571230

隐式地解引用指针并调用函数:

test();    // test函数
func11();  // test函数
func12();  // test函数

显式解引用指针并调用函数:

(*test)();    // test函数
(*func11)();  // test函数
(*func12)();  // test函数

声明一个函数指针,无返回值,有两个参数的:

void (*func2)(int, int) = test2;
func2(11, 12);   // 11 12
(*func2)(13, 14); // 13 14

(*func)()func() 有什么区别?

本质上没有任何区别,它们只是写法上的不同。实际上,编译器在编译时会将 func() 自动转换为 (*func)()。因此,通常我们会选择使用更简洁的写法,直接通过函数指针名来调用指向的函数。

func() 是简洁的语法,它会隐式地解引用指针并调用函数,而 (*func)() 则是显式地解引用指针并调用函数。C++ 编译器允许这两种方式互换,因为它们的含义是完全相同的。


24.2 知识点代码

Lesson24_指针_指针和函数_指向函数的指针.cpp

#include <iostream>
using namespace std;

void test();
void test2(int a, int b);

int main()
{
    std::cout << "指向函数的指针\n";

    #pragma region 知识点二 指向函数的指针

    //声明一个函数指针 指向一个结构一样的函数
    void (*func11)() = nullptr;//test;
    func11 = test;
    void (*func12)() = test;

    //存储了相同的地址 指向test函数
    cout << test << endl;//00007FF6C2571230
    cout << func11 << endl;//00007FF6C2571230
    cout << func12 << endl;//00007FF6C2571230
    
    //隐式地解引用指针并调用函数
    test();//test函数
    func11();//test函数
    func12();//test函数

    //显式解引用指针并调用函数
    (*test)();//test函数
    (*func11)();//test函数
    (*func12)();//test函数

    //声明一个函数指针 无返回值 有两个参数的
    void (*func2)(int, int) = test2;
    func2(11, 12);//11 12
    (*func2)(13, 14);//13 14

    // (*func)() 和 func() 有什么区别?
    // 本质上没有任何区别,它们只是写法上的不同。
    // 实际上,编译器在编译时会将 func() 自动转换为 (*func)()。
    // 因此,通常我们会选择使用更简洁的写法,直接通过函数指针名来调用指向的函数。
    // func() 和 (*func)() 都是调用 func 指向的函数的方式。
    // func() 是简洁的语法,它会隐式地解引用指针并调用函数,而 (*func)() 则是显式地解引用指针并调用函数。
    // C++ 编译器允许这两种方式互换,因为它们的含义是完全相同的。

    #pragma endregion
}

#pragma region 知识点一 函数在内存中的存储

//我们之前学习了变量的存储
//变量是存储在内存中的小房间中的
//那么函数是否存储在内存中呢?
//答案是肯定的
//只不过它的存储区域有所不同!
// 
//当程序启动时,操作系统会将程序的各个部分(包括代码段、数据段、堆和栈)加载到内存中。
//在这个过程中,程序中定义的所有函数的机器码(即执行指令)会被加载到代码段中。
// 
//代码段:
//程序内存中的一部分,专门用于存储可执行代码。它是只读的,防止在执行过程中修改代码。
//而每个函数在代码段中都有一个入口地址
//这个地址指向该函数的第一条指令。
//函数名在编译时被映射为这个地址,使得我们可以通过函数名来调用函数!!

#pragma endregion

#pragma region 知识点二 指向函数的指针

//指向函数的指针(函数指针)在 C++ 中是一种强大的工具
//它允许你通过指针调用函数、实现回调函数、函数数组等功能
//声明语法:
//返回值类型 (*指针名)(参数类型列表)
//例如:
//  int (*function_ptr)(int, int)
//  void (*function_ptr)()
//注意事项:
//1.用函数指针指向函数时,函数的返回类型和参数类型必须和函数指针结构上完全一致
//2.函数指针之所以需要用括号把*和指针名括起来,是用于区分 函数指针 和 返回指针的函数
//3.函数指针一般指 指向函数的指针
//  指针函数一般指 返回类型是指针的函数(之后会专门讲)

void test()
{
    cout << "test函数" << endl;
}

void test2(int a, int b)
{
    cout << a << endl;
    cout << b << endl;
}

#pragma endregion

24.3 练习题

请写出函数指针的声明规则

函数返回值 (*函数指针名)(参数列表)

声明一个返回值为int指针,有三个参数(string、int、float)的函数指针

int* (*func)(string, int, float)


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏