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;
}
相关推荐
A懿轩A2 分钟前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
大胆飞猪1 小时前
C++9--前置++和后置++重载,const,日期类的实现(对前几篇知识点的应用)
c++
1 9 J1 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
夕泠爱吃糖1 小时前
C++中如何实现序列化和反序列化?
服务器·数据库·c++
长潇若雪1 小时前
《类和对象:基础原理全解析(上篇)》
开发语言·c++·经验分享·类和对象
染指11104 小时前
50.第二阶段x86游戏实战2-lua获取本地寻路,跨地图寻路和获取当前地图id
c++·windows·lua·游戏安全·反游戏外挂·游戏逆向·luastudio
Code out the future4 小时前
【C++——临时对象,const T&】
开发语言·c++
sam-zy4 小时前
MFC用List Control 和Picture控件实现界面切换效果
c++·mfc
aaasssdddd965 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
发呆小天才O.oᯅ5 小时前
YOLOv8目标检测——详细记录使用OpenCV的DNN模块进行推理部署C++实现
c++·图像处理·人工智能·opencv·yolo·目标检测·dnn