C语言-指针函数与函数指针及回调函数的使用

本章章节概述:

1、指针函数

2、函数指针

3、指针函数和函数指针的核心区别

4、回调函数

C语言指针进阶:指针函数与函数指针;

指针是C语言中最强大但也最容易混淆的特性之一。我在前面章节已经讲解了指针的基础用法,数组指针与指针数组的区别,今天我们来深入辨析另一组极易混淆的概念-指针函数和函数指针,并讲解基于函数指针实现的回调函数使用方法。这两个概念名字只有语序不同,但本质天差地别,是C语言进阶的核心难点之一。

一、指针函数

指针函数,从名字拆解:"指针" 是修饰词,核心主体是 "函数"。也就是说,指针函数本质上是一个函数,只不过它的返回值类型是一个指针(内存地址)。

示例:

cpp 复制代码
int *pfun(int a, int b);

概念:返回值为指针的函数,叫做指针函数。

作用:用于在函数中返回内存地址,将堆内存、静态变量或全局变量的地址返回给调用者,实现跨函数的内存操作与数据传递。

注意:指针函数绝对不能返回局部变量的地址!因为局部变量在函数执行结束后会被系统自动回收,返回的地址会变成悬空指针,访问它属于未定义行为,会导致程序崩溃。

代码使用示例:

cpp 复制代码
#include "stdio.h"

int *find_max(int arr[], int len);  //指针函数声明:返回int类型的指针

int main()  //主函数
{
    int num[]={1,2,3,4,5,66,7,8,9,10};
    int len_long = sizeof(num) / sizeof(int);

    int *max = find_max(num, len_long);

    printf("数组中最大的值为= %d\n", *max);
    printf("最大值所在的内存地址为:%p\n", max);
    return 0;
}

int *find_max(int arr[], int len)   //指针函数:返回值指针,形参数组和变量,功能数组中找最大值
{
    int *max_p = &arr[0];
    for(int i = 1; i < len; i++)
    {
        if(arr[i] > *max_p)
        {
            max_p = &arr[i];    //更新获取最大值的地址
        }
    }
    return max_p;
}

==========================================
[Running] cd "c:\Users\LiYongFeng\Desktop\Test-C\" && gcc test1.c -o test1 && "c:\Users\LiYongFeng\Desktop\Test-C\"test1
数组中最大的值为= 66
最大值所在的内存地址为:0061FF04

[Done] exited with code=0 in 1.291 seconds

核心要点:指针函数的核心是函数,它的特殊之处只在于返回值是指针,而非常量数值。

二、函数指针

函数指针,从名字拆解:"函数" 是修饰词,核心主体是 "指针"。也就是说,函数指针本质上是一个指针变量,只不过它指向的不是普通变量,而是一个函数的入口地址。

示例:本质是指针,指向函数入口地址的指针,叫做函数指针。

cpp 复制代码
int (*fptr)(int, int);

注意:只有返回值类型、参数个数、参数类型、参数顺序完全一致的函数,才能被同一个函数指针指向。

作用:利用函数指针,可以实现动态调用函数、将函数作为参数传递,是实现回调机制、多态逻辑的基础。

代码使用示例:

cpp 复制代码
#include "stdio.h"
int add(int a, int b);      // 函数声明
int sub(int a, int b);      // 函数声明 

int main()
{
    int (*p_func)(int, int);  // 函数指针声明
    int i=10, j=20;

    p_func = add;
    printf("%d + %d = %d\n", i, j, p_func(i, j));
    p_func = sub;
    printf("%d - %d = %d\n",i,j, p_func(i, j));

    return 0;
}

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

======================================
[Running] cd "c:\Users\LiYongFeng\Desktop\Test-C\" && gcc test1.c -o test1 && "c:\Users\LiYongFeng\Desktop\Test-C\"test1
10 + 20 = 30
10 - 20 = -10

[Done] exited with code=0 in 0.364 seconds

三、指针函数和函数指针的核心区别

很多人分不清这两个概念,核心就是搞不清「谁是主体」。我们从本质、语法、用途三个维度彻底区分开。

1. 本质不同

  • 指针函数:本质是函数,和普通函数地位一样,只是返回值是指针。
  • 函数指针:本质是指针变量,和普通指针地位一样,只是指向的是函数地址。

2. 声明语法不同(最直观区分标志)

关键看*和函数名有没有被括号括起来,注意:括号是灵魂!*和变量名被括号包起来的,就是函数指针;没有括号的,就是指针函数。

概念 声明示例 结合规则
指针函数 int *func(int); ()优先级高于*,func 先和 () 结合,说明是函数;返回值类型是 int*
函数指针 int (*p)(int); 括号改变优先级,p 先和 * 结合,说明是指针;指针指向 int (int) 类型的函数

3. 用途不同

  • 指针函数:用于返回内存地址,比如返回动态分配的内存首地址、返回数组中的元素地址等。
  • 函数指针:用于动态调用函数、作为函数参数传递、实现回调机制、状态机、函数跳转表等。

四、回调函数的使用

回调函数是 C 语言中非常重要的编程机制,它的底层实现完全依赖于函数指针。

概念:如果把一个函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用它所指向的函数时,我们就称这个被调用的函数为回调函数(Callback Function)。

简单理解:回调函数不是由该函数的实现方自己直接调用,而是由另外一个 "框架函数" 在特定时机或条件下,通过传进来的函数指针间接调用。

作用:

  1. 解耦:通用逻辑和具体业务分离,框架不用关心底层具体实现。
  2. 灵活扩展:可以在不修改框架函数的前提下,新增不同的处理逻辑。
  3. 异步通知:常用于事件触发、中断处理、定时任务等场景。

回调函数的使用步骤

  1. 约定回调函数的参数和返回值格式;
  2. 实现符合格式的回调函数(可以有多个);
  3. 定义框架函数,接收函数指针作为参数;
  4. 调用框架函数时,将回调函数的地址传入。
cpp 复制代码
#include "stdio.h"

void print_app1(int num);            //打印形参函数1
void print_app2(int num);            //打印形参函数2
void array_traversal(int arr[], int len, void (*func)(int));

int main()
{
    int arr[] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(int);

    printf("原数组为:\n");
    array_traversal(arr, 5, print_app1);
    printf("乘二后的数组为:\n");
    array_traversal(arr, 5, print_app2);

    return 0;
}

void print_app1(int num)            //打印形参函数
{
    printf("app1: %d\n", num);
}

void print_app2(int num)            //打印形参*2函数
{
    printf("app2: %d\n", num*2);
}

//框架函数 :通用数组遍历
//第三个形参就是完整的函数指针类型:void (*func)(int)
void array_traversal(int arr[], int len, void (*func)(int))
{
    for(int i = 0; i < len; i++)
    {
        func(arr[i]);        //通过函数指针调用回调函数,处理当前元素
    }
    printf("\n");
}

制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!

相关推荐
小oo呆1 小时前
【学习心得】迭代器和可迭代对象
开发语言·python
AC赳赳老秦1 小时前
采集行为合规自检:OpenClaw 自动校验 robots 协议与采集频率,规避违规采集风险
java·开发语言·c++·python·php·deepseek·openclaw
钱栈up1 小时前
mvn compile 卡死在 javac 阶段:一次类型不匹配的排查与修复
java·开发语言
迅猛龙办公室1 小时前
Python输出当前计算机的系统日期和时间
开发语言·前端·python
杨丰玮4182 小时前
C语言基础知识(一)————各类符号的含义与输入输出库(stdio)
c语言·开发语言
程序猿编码2 小时前
工业视觉多任务方案:可编程梯度信息视觉框架,训练评估 + C++ 部署完整实战
开发语言·c++·视觉·推理引擎
水饺编程3 小时前
第1章,了解乌班图环境,使用浏览器和邮箱
c语言·汇编·ubuntu
言乐63 小时前
Python实现语音审核模型
开发语言·python·django·virtualenv·pygame
朝朝辞暮i3 小时前
C++ 第 21 课:struct —— 把一组相关数据打包在一起
开发语言·c++·算法