10.2 指针进阶_函数指针

embedded/2025/3/4 4:57:07/

指针进阶

  • 5. 函数指针
  • 6. 函数指针数组
  • 7. 指向函数指针数组的指针
  • 8. 回调函数

10.1 指针进阶_数组指针
10.3 指针进阶_代码分析

5. 函数指针

void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}
006013B6
006013B6
test和&test都是函数地址

eg

void test(char* pc, int arr[10])
{ }
int main()
{void (*pf)(char*, int arr[]) = test;return 0;
}

eg

int Add(int x, int y)
{return x + y;
}
int main()
{int arr[10] = { 0 };int(*pa)[10] = &arr;//类比int(*pf)(int, int) = &Add;//pf是函数指针变量return 0;
}

使用指针调用函数

int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf)(int, int) = &Add;int r = Add(3, 5);printf("%d\n", r);int m = (*pf)(4, 5);//--> int m = pf(4, 5);//pf和Add一回事printf("%d\n", m);return 0;
}

eg1.代码分析

(*(void (*)())0)();void (*p)()-->p是函数指针
void (*)() -->函数指针类型
(void (*)())0-->强制类型转换, 0转换成 void (*)()0的地址中存放着这个函数
*(void (*)())0-->解引用,调用这个函数
(*(void (*)())0)()-->调用时无参数
(*(void (*)())0)();-->调用0地址处的函数

eg2.代码分析

void (*signal(int , void(*)(int)))(int);void (*p)(int); -->函数指针
void(*)(int)-->函数指针指向一个int类型的参数,返回类型void
signal(int , void(*)(int))--> signal 函数(类型 int ,函数指针类型 void(*)(int))

简化

//typedef重定义
typedef unsigned int uint;
typedef int* ptr_t;typedef int(*parr_t)[10];
typedef int(*pf_t)(int,int);int main()
{uint u1;ptr_t p1;int* p2;return 0;
}
void (*signal(int , void(*)(int)))(int);
--->typedef void(*pf_yt)(int);//void (*signal(int, void(*)(int)))(int);pf_yt signal(int, pf_yt);

6. 函数指针数组

int Add(int x, int y) {return x + y;
}
int Sub(int x, int y) {return x - y;
}
int Mul (int x, int y) {return x * y;
}
int Div(int x, int y) {return x / y;
}
int main() {//int(*pf1)(int, int) = Add;//int(*pf2)(int, int) = Sub;//int(*pf3)(int, int) = Mul;//int(*pf4)(int, int) = Div;//函数指针数组int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };int input = 0;int x = 0;int y = 0;int ret = 0;printf("1.Add 2.Sub 3.Mul 4.Div\n");scanf("%d", &input);printf("输入两个操作数\n");scanf("%d %d", &x, &y);ret = pfArr[input](x, y);printf("ret = %d\n", ret);return 0;
}

7. 指向函数指针数组的指针

int (*pf)(int, int);//函数指针
int (*pfArr[4])(int, int);//函数指针数组pfArr
int (*(*p)[4])(int, int) = &pfArr;//函数指针  数组的地址
//p就是指向函数指针数组的指针

8. 回调函数

回调函数:通过函数指针调用的函数。
把函数的指针(地址)作为参数传递给另一个函数,指针被用来调用其所指向的函数。
回调函数不是由该函数的实现方直接调用,而是由另外的一方调用的。

void menu() {printf("* 1.add  2.sub *\n");printf("* 3.mul  4.div *\n");printf("* 0.exit       *\n");
}
int Add(int x, int y) {return x + y;
}
int Sub(int x, int y) {return x - y;
}
int Mul (int x, int y) {return x * y;
}
int Div(int x, int y) {return x / y;
}
void Calc(int(*pf)(int, int)) {int x = 0;int y = 0;int ret = 0;printf("输入两个操作数\n");scanf("%d %d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}
int main() {int input = 0;int x = 0;int y = 0;int ret = 0;do {menu();printf("请输入> ");scanf("%d", &input);switch (input) {case 1:Calc(Add);//回调函数break;case 2:Calc(Sub);break;case 3:Calc(Mul);break;case 4:Calc(Div);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}

标准库中qsort函数用来排序
qsort

  1. 快速排序
  2. 适合任意类型
void qsort( void* base,//指向需要排序数组的第一个元素size_t num,//排序的元素个数size_t width,//一个元素的大小,单位是字节int(__cdecl* compare)(const void* elem1, const void* elem2)//函数指针类型);
viod* -->无具体类型指针,可以接收任意类型的地址。
不能直接解引用,不能直接进行指针运算。
因为不知道类型,不知道访问多少字节空间。
#include <stdlib.h>
//qsort排序整形
int cmp_int(const void* p1, const void* p2) {return(*(int*)p1 - *(int*)p2);
}
void print(int arr[], int sz){int i = 0;for (i -= 0; i < sz; i++) {printf("%d ", arr[i]);}
}
test1() {int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);//qsort默认是升序qsort(arr, sz, sizeof(arr[0]), cmp_int);print(arr, sz);
}
int main() {test1();return 0;
}

0 1 2 3 4 5 6 7 8 9

//qsort排序结构体数据_age
struct Stu {char name[20];int age;
};
int cmp_stu_by_age(const void* p1, const void* p2) {return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void test2() {struct Stu arr[] = { {"alice",30},{"bob",20},{"ruarua",10} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}
int main() {//test1();test2();return 0;
}
名称类型
arr0x009af81c {{name=0x006ff7ac “alice” age=30 }, {name=0x006ff7c4 “bob” age=20 }, {name=0x006ff7dc “ruarua” …}}Stu[3]
[0]{name=0x006ff7ac"alice" age=30 }Stu
[1]{name=0x006ff7c4 “bob” age=20 }Stu
[2]{name=0x006ff7dc “ruarua” age=10 }Stu
–>
名称类型
arr0x006ff7ac {{name=0x006ff7ac “ruarua” age=10 }, {name=0x006ff7c4 “bob” age=20 }, {name=0x006ff7dc “alice” …}}Stu[3]
[0]{name=0x006ff7ac “ruarua” age=10 }Stu
[1]{name=0x006ff7c4 “bob” age=20 }Stu
[2]{name=0x006ff7dc “alice” age=30 }Stu
//qsort排序结构体数据_name
struct Stu {char name[20];int age;
};
int cmp_stu_by_name(const void* p1, const void* p2) {return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void test3() {struct Stu arr[] = { {"zalice",30},{"tbob",20},{"aruarua",10} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
int main() {//test1();//test2();test3();return 0;
}
名称类型
arr0x0054f6b4 {{name=0x0054f6b4 “zalice” age=30 }, {name=0x0054f6cc “tbob” age=20 }, {name=0x0054f6e4 “aruarua” …}}Stu[3]
[0]{name=0x0054f6b4 “zalice” age=30 }Stu
[1]{name=0x0054f6cc “tbob” age=20 }Stu
[2]{name=0x0054f6e4 “aruarua” age=10 }Stu

–>

名称类型
arr0x0054f6b4 {{name=0x0054f6b4 “aruarua” age=10 }, {name=0x0054f6cc “tbob” age=20 }, {name=0x0054f6e4 “zalice” …}}Stu[3]
[0]{name=0x0054f6b4 “aruarua” age=10 }Stu
[1]{name=0x0054f6cc “tbob” age=20 }Stu
[2]{name=0x0054f6e4 “zalice” age=30 }Stu

10.1 指针进阶_数组指针
10.3 指针进阶_代码分析


http://www.ppmy.cn/embedded/169810.html

相关文章

【Linux网络-HTTP协议】HTTP基础概念+构建HTTP

代码定位&#xff1a;南毅c/Linux - Gitee.com HTTP协议 介绍 虽然我们说&#xff0c;应用层协议是我们程序猿自己定的.但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用。HTTP(超文本传输协议)就是其中之一。 在互联网世界中&#xff0c…

新时代,科技助力运动旅游开启新潮流

新时代&#xff0c;科技助力运动旅游开启新潮流 运动&科技旅游&科技 其实说到运动旅游&#xff0c;这应该是两个方面&#xff1a;运动和旅游&#xff0c;那么下面就从运动和旅游两个方面来理解一下个人认为的哪些科技手段可以助力行程。 运动&科技 说到运动&…

el-input实现金额输入

需求&#xff1a;想要实现一个输入金额的el-input&#xff0c;限制只能输入数字和一个小数点。失焦数字转千分位&#xff0c;聚焦转为数字&#xff0c;超过最大值&#xff0c;红字提示 效果图 失焦 聚焦 报错效果 // 组件limitDialog <template><el-dialog:visible.s…

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…

第002文-kali虚拟机安全与网络配置

1、kali系统介绍 kali是一个基于Linux kernel的操作系统&#xff0c;由BackTrack(简称BT)发展而来。BackTrack是2006年推出的一个用于渗透测试及黑客攻防的专用平台&#xff0c;基于Knoppix(linux的一个发行版)开发。BackTrack版本周期&#xff1a;2006年的起始版本BackTrack …

具身智能(Embodied AI)的物理交互基准测试:构建真实世界的智能体评估体系

文章目录 引言:从虚拟到物理的智能跃迁一、具身智能测试体系设计1.1 评估维度矩阵1.2 测试平台技术栈二、核心测试场景构建2.1 基础运动能力测试集2.2 复杂操作任务设计三、物理仿真引擎关键技术3.1 高精度接触力学模型3.2 传感器噪声模拟四、评估指标体系4.1 量化指标公式4.2…

虚拟机中的指示命令

1. 复制文件&#xff1a;cp 源文件 目标文件&#xff08;cp file1.txt file2.txt&#xff09; 2. 复制文件夹&#xff1a;cp -r 源文件夹 目标文件夹&#xff08;cp -r dir1 dir2&#xff09; 3. 创建一个空的文件&#xff1a;touch file1.txt 4. 创建一个空目录&a…

Spring的构造注入

1.开发步骤2.构造方法的重载 2.1参数个数不同2.2构造参数个数相同时 3.注入总结 注入&#xff1a;通过Spring的配置文件&#xff0c;为成员变量赋值 Set注入&#xff1a;Spring调用Set方法&#xff0c;通过配置文件&#xff0c;为成员变量赋值 构造注入&#xff1a;Spring调用…