拓冰建站拓冰建站
首页 / 资讯中心 / 正文

C 语言|高级指针:数组配套指针与函数指针 —— 学习笔记

附图完整梳理整套C语言指针知识体系指针底层逻辑、各类指针分类已有完整梳理本文不再赘述。本文围绕数组配套指针、函数指针含函数指针数组两大核心难点展开解析前者依托数组与指针的内在关联逐层拆解后者结合指针实操场景逐一阐述。文章目录数组配套指针变量 结合数组与指针内在关联剖析数组与指针底层脉络梳理数组名底层释义指针访问数组实现指针数组与数组指针变量概念辨析指针数组数组指针变量函数指针与函数数组指针依托指针实操应用场景阐述函数指针底层释义实际应用——回调函数函数指针数组底层释义实际应用——转移表小结数组配套指针变量 结合数组与指针内在关联剖析数组与指针底层脉络梳理数组名底层释义intarr[]{1,2,3,4,5];printf(arr %p, arr); // printf(arr[0]%p,arr[0])数组名是首元素的地址多数场景中数组名 数组首元素地址arr与arr[0]内存一致。但有两处特例数组名不再指代首元素sizrof(数组名:指代完整数组计算数组整体占用字节数组名:获取数组整体地址与首元素地址无关。指针访问数组实现由上文可知数组名等同数组首元素地址。将该地址赋值给指针变量后依靠指针偏移即可遍历数组全部元素。#includestdio.hintmain(){intarr[]{1,2,3,4,5];int*parr;for(inti0;i5;i){printf(%d,*(pi);}return0;}指针数组与数组指针变量概念辨析指针数组指针数组属于特殊数组数组中每一个元素都是指针同类衍生数组还有许多例如字符指针数组浮点型指针数组。数组指针变量定义专门用来存储整个数组地址的指针intarr[10]{0};int(*p)[10]arr;语法解析[ ]优先级高于**p必须加括号不加括号就变成指针数组后方[10]限制只能指向长度为 10 的 int 数组仅能赋值arr不能直接写arr二者类型不匹配核心用途用途 1二维数组函数传参高频考题#includestdio.h// int (*p)[5] 数组指针接收3行5列二维数组每行是长度5的int数组voidtest(int(*p)[5],intr,intc){inti0;intj0;for(i0;ir;i){for(j0;jc;j){// pi指向第i行的起始地址// *(pi)解引用得到第i行首元素地址// *(pi)j偏移到第i行第j列元素地址// *()取出地址里的数值printf(%d ,*(*(pi)j));}printf(\n);}}intmain(){intarr[3][5]{{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};test(arr,3,5);return0;}用途 2p1 跳过一整个数组步长为数组总字节int (*p)[5]数组指针指向长度为 5 的整型数组p 1不会只偏移 1 个 int而是一次性偏移整个数组占用的字节5*420 字节对比普通 int* 指针步长特性是数组指针核心考点函数指针与函数数组指针依托指针实操应用场景阐述函数指针底层释义普通指针用来存放普通变量、数组的内存地址。函数指针变量。专门用来存放函数的入口地址。函数加载进内存会拥有一块存储空间拥有起始地址函数名本身就代表该函数的入口地址。#includestdio.hvoidtest(inta){printf(%d\n,a);}intmain(void){//定义函数指针变量(*p)括号不可丢void(*p)(int);ptest;// p test 赋值存入test函数入口地址p初始为无效随机值必须赋值才能调用(*p)(200);// (p)(200) 解引用获取函数本体完成调用return0;}void (*p)(int); 中(*p)的括号绝对不能丢失。若写成void *p(int);语义变为函数声明该函数返回 void*指针不再是函数指针。C 语言语法特性函数指针调用时*解引用符号可以省略p()与(*p)()完全等价。实际应用——回调函数题目要求编写一款简易计算器程序借助函数指针作为入参实现加、减、乘、除四则运算。回调优势代码解耦通用计算函数无需绑定具体运算可灵活传入不同功能函数#includestdio.hintAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}// 回调承载函数接收函数指针形参intcalc(intx,inty,int(*fp)(int,int)){returnfp(x,y);// fp接收外部传入的函数地址完成回调调用}intmain(){intinput0;intx0;inty0;intr0;do{printf(请选择);scanf(%d,input);if(input1input4){printf(请输入2个操作数);scanf(%d%d,x,y);if(input1)rcalc(x,y,Add);elseif(input2)rcalc(x,y,Sub);elseif(input3)rcalc(x,y,Mul);elseif(input4)rcalc(x,y,Div);printf(结果是%d\n,r);}elseif(input0){printf(退出计算器\n);}else{printf(输入错误请输入0~4的值\n);}}while(input);return0;}拓展typedef 简化例题内的函数指针类型原始复杂声明int (*fp)(int,int)代表接收两个 int、返回 int 类型的函数指针typedef int (*Func)(int,int);给该函数指针类型设置别名 Func简化之后函数写法如下typedefint(*Func)(int,int);intcalc(intx,inty,Func fp){returnfp(x,y);}函数指针数组底层释义普通数组存放的是普通数据int、char 等。函数指针数组数组里面每一个元素都是函数指针变量用来存放一批函数的入口地址。voidfun1(){printf(函数1\n);}voidfun2(){printf(函数2\n);}intmain(void){//定义函数指针数组void(*pfArr[])(void){fun1,fun2};pfArr[0]();//取下标0的函数指针调用fun1pfArr[1]();//取下标1的函数指针调用fun2return0;void (*pfArr[])(void):pfArr[]代表这是一个数组(*pfArr[])数组中存储的是指针void ()指针指向无参、无返回值的函数实际应用——转移表题目承接上一道计算器例题使用函数指针数组搭建转移表完成四则运算。如将加、减、乘、除四个函数的入口地址全部存入函数指针数组依靠输入的选项下标直接调用对应运算函数。转移表优势利用数组下标直接索引对应函数替代冗长的 if‑else /switch 分支#includestdio.hintAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}// fp 就是函数指针变量intcalc(intx,inty,int(*fp)(int,int)){returnfp(x,y);}intmain(){intinput0;intx0;inty0;intr0;do{printf(请选择);scanf(%d,input);if(input1input4){printf(请输入2个操作数);scanf(%d%d,x,y);if(input1)rcalc(x,y,Add);elseif(input2)rcalc(x,y,Sub);elseif(input3)rcalc(x,y,Mul);elseif(input4)rcalc(x,y,Div);printf(结果是%d\n,r);}elseif(input0){printf(退出计算器\n);}else{printf(输入错误请输入0~4的值\n);}}while(input);return0;}扩展typedef 简化写法// 给函数指针类型起别名typedefint(*Func)(int,int);// 1、函数指针变量回调使用intcalc(intx,inty,Func fp){returnfp(x,y);}// 2、函数指针数组转移表专用Func pfArr[]{NULL,Add,Sub,Mul,Div};小结函数指针变量单个指针存放一个函数地址多用于回调函数指针数组数组容器存放一组函数地址用作转移表依靠下标选择调用函数
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门