函数指针
定义
函数指针本质上是指针,是一个指向函数的指针。函数都有一个入口地址,所谓指向函数的指针,就是指向函数的入口地址(这里的函数名就代表入口地址)
函数指针存在的意义:
让函数多了一种调用方式
函数指针可以作为形参,可以形式调用(回调函数)
遵循:先有函数,后有指针
语法
返回类型(*指针变量名)(形参列表)
举例
int (*fun)(int a,int b);
int(*fun)(int,int);
函数指针的初始化
①定义的同时赋值
//函数指针需要依赖函数,先有函数,后有指针
//定义一个普通函数
int add(int a,int b){return a + b;}
//定义一个函数指针,并初始化
//观察,函数指针的返回类型和指向的函数的返回类型一致,函数指针的形参个数、类型、位置和指向的函数的参数一致。
int (*p)(int a,int b) = add;//函数指针p指向函数add,这里的add不能带(),add就代表函数的入口地址
②先定义,后赋值
//定义一个普通函数
int add(int a,int b){return a + b;}
int (*p)(int ,int ) ;//形参列表的参数名可以省略
p = add;//此时是将add的入口地址赋值给指针p
注意:
函数指针指向的函数要和函数指针定义的返回值类型,形参列表对应,否则编译报错
函数指针是指针,但不能指针运算,如p++等,没有实际意义
函数指针作为形参,可以形成回调
函数指针作为形参,函数调用时的实参只能是与之对应的函数名,不能带小括号()
函数指针的形参列表中的变量名可以省略
/*************************************************************************
> File Name: demo01.c
> Author: 千夕
> Description:
> Created Time: 2025年07月29日 星期二 09时09分45秒
************************************************************************/
#include <stdio.h>
/**
*
* */
int get_max(int a,int b)
{
return a > b ? a : b;
}
int main(int argc,char *argv[])
{
int a = 3,b = 4,max;
max = get_max(a,b);
printf("%d,%d中最大值是:%d\n",a,b,max);
int(*p)(int ,int) = get_max;
max = p(a,b);
printf("%d,%d中最大值是:%d\n",a,b,max);
max = (*p)(a,b);
printf("%d,%d中最大值是:%d\n",a,b,max);
return 0;
}
运行结果:
回调函数
定义
回调函数就是通过函数指针调用的函数.。如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时。我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
为什么要用回调函数
因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。
简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
案例
/*************************************************************************
> File Name: demo02.c
> Author: 千夕
> Description:
> Created Time: 2025年07月29日 星期二 09时26分31秒
************************************************************************/
#include <stdio.h>
/*回调函数*/
int callback_1(int a)
{
printf("hello tihs is callback_1:a = %d\n",a);
return a;
}
/*
*回调函数2
* */
int callback_2(int b)
{
printf("hello tihs is callback_2:b = %d\n",b);
return b;
}
/*
*回调函数3
* */
int callback_3(int c)
{
printf("hello tihs is callback_2:b = %d\n",c);
return c;
}
int handle(int x,int(*callback)(int))
{
printf("日志:开始执行任务!\n");
int res = callback(x);
printf("日志:执行结果!%d\n",res);
printf("日志:结束执行任务!\n");
}
int main(int argc,char *argv[])
{
handle(100,callback_1);
handle(200,callback_2);
handle(300,callback_3);
return 0;
}
运行结果:
二级指针
定义
二级指针(多重指针)用于存储一级指针的地址,需要两次解引用才能访问原始数据。
int a = 10; //a是普通变量,也就是原始数据
int *p = &a; //一级指针,p指向a,解引用1次就可以获取a的值
printf("%d\n",*p);//10
int **w = &p; // 二级指针,w指向p,解引用2次就可以获取a的值
printf("%d\n", **w);// 10
int ***k = &w; // 三级指针,k指向w,解引用3次就可以获取a的值
printf("%d\n", ***k); // 10 int a1 = ***k; int *a2 = **k; int **a3
= *k; int ***a4 = k;
语法
数据类型 **指针变量名 = 指针数组的数组名 | 一级指针的地址
特点:
① 与指针数组的等效性 二级指针与指针数组在某些时候存在等效性,但与二维数组不等效。二维数组名是数组指针类型,如 int (*)[3] ,而非二级指针。
// 指针数组
int arr[] = {11,22,33};
int *arr_[] = {&arr[0],&arr[1],&arr[2]};
// 二级指针接收指针数组
char *str[3] = {"abc","aaa034","12a12"};
char **p = str; // p:数组首地址,行地址,默认0行 *p:列地址,默认0行0列
**p:列元素
/*********************************************************************
****
> File Name: demo03.c
> Author: 千夕
> Description:
> Created Time: 2025年07月29日 星期二 10时27分05秒
**********************************************************************
**/
#include <stdio.h>
int main(int argc,char *argv[])
{
char *str[3] = {"abc","aaa034","12a12"};
char **p = str;
// 打印字符串
// for (int i = 0; i < 3; i++)
// {
// printf("%s\n", *p);
// p++;
// }
// 打印字符
int i = 0;
while(**p != '\0')
{
printf("%-2c",**p);
(*p)++;
}
printf("\n");
return 0;
}
② 与二维数组的差异 二维数组名是数组指针类型,直接赋值给二级指针会导致类型不匹配
// 数组指针可以指向一个二维数组
int arr[2][3] = {{1,3,5},{11,33,55}};
int (*p)[3] = arr;
// 二级指针不等效二维数组
int **k = arr; // 编译报错 arr类型 int(*)[3] 不兼容 k类型 int**