C++指针解读(7)-- 指针和函数

前面我们讲过用指针变量作为函数参数。这里讲指向函数的指针变量和返回指针的函数。

1、指向函数的指针变量

跟变量一样,函数也会存储在内存空间中,函数的内存空间有一个起始地址,每次调用函数时就从该入口地址开始执行函数代码。

既然函数有地址,我们就可以定义一个指向该函数的指针变量。比如,我们可以定义这样的指针变量:

复制代码
int (*pfun)();

从右往左读,先是(),表示这是一个函数;然后是(*pfun),表示一个指针指向这个函数;最后是void,表示这个函数返回int。

如果我们把指针的挂号去掉:

复制代码
int *pfun();

则表示一个返回int*类型的函数。

所以,定义指向函数的指针变量的形式为:

(1)类型名 (*指针变量名)(函数参数列表)

(2)typedef 类型名 (*指针变量名)(函数参数列表)

这里必须注意,一个函数的指针变量只能指向定义时指定的类型的函数。比如int (*p)()表示函数指针变量p可以指向返回值是int的无参数函数。

2、函数指针的使用

我们来看一个使用函数指针的例子:

复制代码
int max(int a, int b) {
    if (a > b) {
        return a;
    }
    else {
        return b;
    }
}

int main()
{
    int a = 3;
    int b = 7;

    int (*p)(int, int);
    p = max;
    int ret = p(3, 7);
    //也可以这么调用
    //int ret = (*p)(3, 7);
    printf(" max = %d\n", ret);

    return 0;
}

使用函数指针的注意事项:

(1)函数指针只能指向定义时指定的函数类型。比如int (*p)(int, int)就只能指向返回值是int,形参列表是2个int的函数。比如int max(int a, int b); int min(int a, int b)等这样的函数都可以。

(2)函数指针变量要调用哪个函数,就让指针指向哪个函数。

比如p = max,这里形参的列表是不用写的,只要写函数名就可以了。因为函数名代表函数的入口地址,让函数指针指向这个入口地址就可以了。

(3)用函数指针变量代替函数运行,比如p(a, b)。

(4)函数指针变量不能进行算术运算,p+n, p++等都是错误的。

3、用函数的指针作函数参数

指向函数的指针可以作为函数参数,把函数的指针作为形参,这样就能够在被调用函数中使用实参函数。

有下面几种传递函数指针的方式:

(1)显式地将形参定义为指向函数的指针

void func(int nValue,int (*pf)(int,int));

(2)第二个形参为函数类型,会自动转换为指向此类函数的指针

void func(int nValue,int pf(int,int));

(3)

typedef int (*PF)(int, int);

void func(int nValue, PF pf)

例子:

复制代码
int add(int i, int j) {
    return i + j;
}

int sub(int i, int j) {
    return i - j;
}

typedef int (*pfun)(int i, int j);
int compute(pfun fun, int i, int j) {
    return fun(i, j);
}

int main()
{
    int a = 3;
    int b = 7;
    int (*pf1)(int i, int j);
    pf1 = sub;

    std::cout << compute(pf1, b, a) << std::endl;

    return 0;
}

4、函数指针数组

函数指针也可以存放在数组中。

假如有这么一个应用场景,系统需要根据输入的参数来选择需要执行的具体函数。

输入'+',则执行add()函数;输入'-',则执行sub()函数。

复制代码
typedef int (*operation)(int i, int j);
operation ops[128] = { 0 };
ops['+'] = add;
ops['-'] = sub;

operation op1 = ops['+'];
printf(" 3 + 4 = %d\n", op1(3, 4));

operation op2 = ops['-'];
printf(" 7 - 3 = %d\n", op2(7, 3));

这里我们用'+', '-'作为数组的索引,因为char其实就是int类型,我们把数组长度定义为128,是因为ASCII共有128个字符,这样每个ASCII字符都能作为数组的索引存放。

5、返回指针值的函数

定义返回指针值的函数的形式为:

类型名 *函数名(参数列表)

返回指针时要注意这几种情况:

(1)如果返回的是函数内部局部变量的指针,那么这个指针出函数作用域时,其指向的对象已经失效。这种情况下就成了迷途指针或悬空指针。

复制代码
int* invalidPointer() {
    int tmp = 3;

    return &tmp; //出函数后tmp对象已被释放,返回的指针成了: 迷途指针/悬空指针
}

(2)如果是在函数内部动态分配了内存的指针,记得在函数外部释放内存,避免产生内存泄漏。

复制代码
int* localPointer() {
    int* pi = (int*)malloc(sizeof(int));
    return pi;
}
相关推荐
武当豆豆1 小时前
C++编程学习阶段性总结
开发语言·c++
A7bert7773 小时前
【YOLOv8-obb部署至RK3588】模型训练→转换RKNN→开发板部署
linux·c++·人工智能·python·yolo
zyx没烦恼4 小时前
五种IO模型
开发语言·c++
EutoCool4 小时前
Qt窗口:菜单栏
开发语言·c++·嵌入式硬件·qt·前端框架
圆头猫爹6 小时前
第34次CCF-CSP认证第4题,货物调度
c++·算法·动态规划
十五年专注C++开发7 小时前
hiredis: 一个轻量级、高性能的 C 语言 Redis 客户端库
开发语言·数据库·c++·redis·缓存
hi0_67 小时前
03 数组 VS 链表
java·数据结构·c++·笔记·算法·链表
碧海蓝天20228 小时前
C++法则21:避免将#include放在命名空间内部。
开发语言·c++
CodeWithMe8 小时前
【读书笔记】《C++ Software Design》第一章《The Art of Software Design》
开发语言·c++
Tanecious.9 小时前
C++--红黑树
开发语言·c++