組配套指針與函數(shù)指針 —— 學(xué)習(xí)筆記)
附圖完整梳理整套C語言指針知識體系指針底層邏輯、各類指針分類已有完整梳理本文不再贅述。本文圍繞數(shù)組配套指針、函數(shù)指針含函數(shù)指針數(shù)組兩大核心難點(diǎn)展開解析前者依托數(shù)組與指針的內(nèi)在關(guān)聯(lián)逐層拆解后者結(jié)合指針實(shí)操場景逐一闡述。文章目錄數(shù)組配套指針變量 結(jié)合數(shù)組與指針內(nèi)在關(guān)聯(lián)剖析數(shù)組與指針底層脈絡(luò)梳理數(shù)組名底層釋義指針訪問數(shù)組實(shí)現(xiàn)指針數(shù)組與數(shù)組指針變量概念辨析指針數(shù)組數(shù)組指針變量函數(shù)指針與函數(shù)數(shù)組指針依托指針實(shí)操應(yīng)用場景闡述函數(shù)指針底層釋義實(shí)際應(yīng)用——回調(diào)函數(shù)函數(shù)指針數(shù)組底層釋義實(shí)際應(yīng)用——轉(zhuǎn)移表小結(jié)數(shù)組配套指針變量 結(jié)合數(shù)組與指針內(nèi)在關(guān)聯(lián)剖析數(shù)組與指針底層脈絡(luò)梳理數(shù)組名底層釋義intarr[]{1,2,3,4,5];printf(arr %p, arr); // printf(arr[0]%p,arr[0])數(shù)組名是首元素的地址多數(shù)場景中數(shù)組名 數(shù)組首元素地址arr與arr[0]內(nèi)存一致。但有兩處特例數(shù)組名不再指代首元素sizrof(數(shù)組名:指代完整數(shù)組計(jì)算數(shù)組整體占用字節(jié)數(shù)組名:獲取數(shù)組整體地址與首元素地址無關(guān)。指針訪問數(shù)組實(shí)現(xiàn)由上文可知數(shù)組名等同數(shù)組首元素地址。將該地址賦值給指針變量后依靠指針偏移即可遍歷數(shù)組全部元素。#includestdio.hintmain(){intarr[]{1,2,3,4,5];int*parr;for(inti0;i5;i){printf(%d,*(pi);}return0;}指針數(shù)組與數(shù)組指針變量概念辨析指針數(shù)組指針數(shù)組屬于特殊數(shù)組數(shù)組中每一個元素都是指針同類衍生數(shù)組還有許多例如字符指針數(shù)組浮點(diǎn)型指針數(shù)組。數(shù)組指針變量定義專門用來存儲整個數(shù)組地址的指針intarr[10]{0};int(*p)[10]arr;語法解析[ ]優(yōu)先級高于**p必須加括號不加括號就變成指針數(shù)組后方[10]限制只能指向長度為 10 的 int 數(shù)組僅能賦值arr不能直接寫arr二者類型不匹配核心用途用途 1二維數(shù)組函數(shù)傳參高頻考題#includestdio.h// int (*p)[5] 數(shù)組指針接收3行5列二維數(shù)組每行是長度5的int數(shù)組voidtest(int(*p)[5],intr,intc){inti0;intj0;for(i0;ir;i){for(j0;jc;j){// pi指向第i行的起始地址// *(pi)解引用得到第i行首元素地址// *(pi)j偏移到第i行第j列元素地址// *()取出地址里的數(shù)值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 跳過一整個數(shù)組步長為數(shù)組總字節(jié)int (*p)[5]數(shù)組指針指向長度為 5 的整型數(shù)組p 1不會只偏移 1 個 int而是一次性偏移整個數(shù)組占用的字節(jié)5*420 字節(jié)對比普通 int* 指針步長特性是數(shù)組指針核心考點(diǎn)函數(shù)指針與函數(shù)數(shù)組指針依托指針實(shí)操應(yīng)用場景闡述函數(shù)指針底層釋義普通指針用來存放普通變量、數(shù)組的內(nèi)存地址。函數(shù)指針變量。專門用來存放函數(shù)的入口地址。函數(shù)加載進(jìn)內(nèi)存會擁有一塊存儲空間擁有起始地址函數(shù)名本身就代表該函數(shù)的入口地址。#includestdio.hvoidtest(inta){printf(%d\n,a);}intmain(void){//定義函數(shù)指針變量(*p)括號不可丟void(*p)(int);ptest;// p test 賦值存入test函數(shù)入口地址p初始為無效隨機(jī)值必須賦值才能調(diào)用(*p)(200);// (p)(200) 解引用獲取函數(shù)本體完成調(diào)用return0;}void (*p)(int); 中(*p)的括號絕對不能丟失。若寫成void *p(int);語義變?yōu)楹瘮?shù)聲明該函數(shù)返回 void*指針不再是函數(shù)指針。C 語言語法特性函數(shù)指針調(diào)用時*解引用符號可以省略p()與(*p)()完全等價。實(shí)際應(yīng)用——回調(diào)函數(shù)題目要求編寫一款簡易計(jì)算器程序借助函數(shù)指針作為入?yún)?shí)現(xiàn)加、減、乘、除四則運(yùn)算?;卣{(diào)優(yōu)勢代碼解耦通用計(jì)算函數(shù)無需綁定具體運(yùn)算可靈活傳入不同功能函數(shù)#includestdio.hintAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}// 回調(diào)承載函數(shù)接收函數(shù)指針形參intcalc(intx,inty,int(*fp)(int,int)){returnfp(x,y);// fp接收外部傳入的函數(shù)地址完成回調(diào)調(diào)用}intmain(){intinput0;intx0;inty0;intr0;do{printf(請選擇);scanf(%d,input);if(input1input4){printf(請輸入2個操作數(shù));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(結(jié)果是%d\n,r);}elseif(input0){printf(退出計(jì)算器\n);}else{printf(輸入錯誤請輸入0~4的值\n);}}while(input);return0;}拓展typedef 簡化例題內(nèi)的函數(shù)指針類型原始復(fù)雜聲明int (*fp)(int,int)代表接收兩個 int、返回 int 類型的函數(shù)指針typedef int (*Func)(int,int);給該函數(shù)指針類型設(shè)置別名 Func簡化之后函數(shù)寫法如下typedefint(*Func)(int,int);intcalc(intx,inty,Func fp){returnfp(x,y);}函數(shù)指針數(shù)組底層釋義普通數(shù)組存放的是普通數(shù)據(jù)int、char 等。函數(shù)指針數(shù)組數(shù)組里面每一個元素都是函數(shù)指針變量用來存放一批函數(shù)的入口地址。voidfun1(){printf(函數(shù)1\n);}voidfun2(){printf(函數(shù)2\n);}intmain(void){//定義函數(shù)指針數(shù)組void(*pfArr[])(void){fun1,fun2};pfArr[0]();//取下標(biāo)0的函數(shù)指針調(diào)用fun1pfArr[1]();//取下標(biāo)1的函數(shù)指針調(diào)用fun2return0;void (*pfArr[])(void):pfArr[]代表這是一個數(shù)組(*pfArr[])數(shù)組中存儲的是指針void ()指針指向無參、無返回值的函數(shù)實(shí)際應(yīng)用——轉(zhuǎn)移表題目承接上一道計(jì)算器例題使用函數(shù)指針數(shù)組搭建轉(zhuǎn)移表完成四則運(yùn)算。如將加、減、乘、除四個函數(shù)的入口地址全部存入函數(shù)指針數(shù)組依靠輸入的選項(xiàng)下標(biāo)直接調(diào)用對應(yīng)運(yùn)算函數(shù)。轉(zhuǎn)移表優(yōu)勢利用數(shù)組下標(biāo)直接索引對應(yīng)函數(shù)替代冗長的 if?else /switch 分支#includestdio.hintAdd(intx,inty){returnxy;}intSub(intx,inty){returnx-y;}intMul(intx,inty){returnx*y;}intDiv(intx,inty){returnx/y;}// fp 就是函數(shù)指針變量intcalc(intx,inty,int(*fp)(int,int)){returnfp(x,y);}intmain(){intinput0;intx0;inty0;intr0;do{printf(請選擇);scanf(%d,input);if(input1input4){printf(請輸入2個操作數(shù));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(結(jié)果是%d\n,r);}elseif(input0){printf(退出計(jì)算器\n);}else{printf(輸入錯誤請輸入0~4的值\n);}}while(input);return0;}擴(kuò)展typedef 簡化寫法// 給函數(shù)指針類型起別名typedefint(*Func)(int,int);// 1、函數(shù)指針變量回調(diào)使用intcalc(intx,inty,Func fp){returnfp(x,y);}// 2、函數(shù)指針數(shù)組轉(zhuǎn)移表專用Func pfArr[]{NULL,Add,Sub,Mul,Div};小結(jié)函數(shù)指針變量單個指針存放一個函數(shù)地址多用于回調(diào)函數(shù)指針數(shù)組數(shù)組容器存放一組函數(shù)地址用作轉(zhuǎn)移表依靠下標(biāo)選擇調(diào)用函數(shù)