自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我們一起聊聊指針與函數(shù)

開發(fā) 前端
日常開發(fā)中,我還真沒找到指針函數(shù)的“優(yōu)點”,讓我覺得某個功能必須用指針函數(shù)實現(xiàn),或用指針函數(shù)實現(xiàn)后代碼更整潔,提高代碼可讀性。

指針函數(shù)

指針函數(shù),從名字上看它本質(zhì)上是一個函數(shù)。指針函數(shù):返回值類型是指針的函數(shù)。函數(shù)聲明如下:

int *plusfunction(int a,int b);

當(dāng)然也可以寫成如下格式:

int* plusfunction(int a,int b);

讓指針標(biāo)志 * 與int緊貼在一起,而與函數(shù)名f間隔開,這樣看起來就明了些了,plusfunction是函數(shù)名,返回值類型是一個int類型的指針。

指針函數(shù)就是一個普通的函數(shù),普通到僅僅是因為它的函數(shù)返回值是指針而已。

#include <stdio.h>
#include <stdlib.h>
int* plusfunction(int a,int b);
int main()
{
int *p = NULL;
p = plusfunction(1,2);
printf("*p is %d\n",*p);
free(p);
return(0);
}

int* plusfunction(int a,int b)
{
int *p = (int *) malloc( sizeof(int) );
*p = a + b;
return(p);
}

這是一個簡單的指針函數(shù)的例子,運行結(jié)果如下,本文代碼在VScode平臺運行,使用方法《使用VScode調(diào)試C語言》。

不過我有個疑問,使用指針函數(shù),和函數(shù)入?yún)⑹侵羔樣惺裁春锰幠???

#include <stdio.h>
#include <stdlib.h>
void plusfunction(int a,int b,int *p);
int main()
{
int *p = NULL;
p = (int *) malloc(sizeof(int) );
plusfunction(1,2,p);
printf("*p is %d\n",*p);
free(p);
return(0);
}

void plusfunction(int a,int b,int *p)
{
*p = a + b;
}

這樣執(zhí)行也是沒問題的啊,當(dāng)然我也發(fā)現(xiàn)了指針函數(shù)的好處,就是可以把函數(shù)作為另一個函數(shù)的入?yún)ⅰ?/p>

testfunction(plusfunction(1,2));

在這點上用第二種方法,將指針作為函數(shù)入?yún)⑹遣恍械摹?/p>

還有,將指針作為函數(shù)入?yún)⑶靶枰蛑羔樕暾垉?nèi)存,而指針函數(shù)卻不用。

除去這兩點,日常開發(fā)中,我還真沒找到指針函數(shù)的“優(yōu)點”,讓我覺得某個功能必須用指針函數(shù)實現(xiàn),或用指針函數(shù)實現(xiàn)后代碼更整潔,提高代碼可讀性。

函數(shù)指針

函數(shù)指針,本質(zhì)上他是一個指針,并不是一個函數(shù)。在C語言中有些概念是一脈相承的,之前的推文《指針與數(shù)組》,數(shù)組指針和指針數(shù)組的概念更有效幫你理解函數(shù)指針和指針函數(shù)。函數(shù)指針說的就是一個指針,但這個指針指向的函數(shù),不是普通的基本數(shù)據(jù)類型或者類對象。函數(shù)指針定義如下:

int (*f)(int a,int b);//聲明函數(shù)指針

和指針函數(shù)的定義對比可以看到,函數(shù)指針與指針函數(shù)的最大區(qū)別是函數(shù)指針的函數(shù)名是一個指針,即函數(shù)名前面有一個指針類型的標(biāo)志型號“*”。注意指針函數(shù)與函數(shù)指針表示方法的不同,千萬不要混淆。最簡單的辨別方式就是看函數(shù)名前面的指針*號有沒有被括號()包含,如果被包含就是函數(shù)指針,反之則是指針函數(shù)。當(dāng)然,函數(shù)指針的返回值也可以是指針。簡單的函數(shù)調(diào)用示例:

#include <stdio.h>
void MyFun(int a);
int main()
{
MyFun(10);
return(0);
}
void MyFun(int a)
{
printf("a is %d\n",a);
}

這是一個再簡單不過的函數(shù)調(diào)用了,其實他還可以寫作下面格式:

#include <stdio.h>
void MyFun(int a);
int main()
{
(*MyFun)(10);
return(0);
}
void MyFun(int a)
{
printf("a is %d\n",a);
}

這個代碼是正常運行的,也就是說(*MyFun)(10);和MyFun(10);是一樣的,在這里強(qiáng)烈建議沒有看過《指針與數(shù)組》的同學(xué),先看一下。在教材和資料中,都會講到數(shù)組名就是指向數(shù)組第一個數(shù)據(jù)的常量指針。從上面例子看到,函數(shù)名貌似也是“常量指針”。數(shù)組中,可以將數(shù)組名賦給一個指針,然后通過指針訪問數(shù)組中的內(nèi)容,那么我們就可以定義一個函數(shù)指針,將函數(shù)名賦給函數(shù)指針,通過這個函數(shù)指針調(diào)用函數(shù)。

#include <stdio.h>
void MyFun(int a);/* 這個聲明也可寫成:void MyFun( int )*/
void (*FunP)(int);/*也可聲明成void(*FunP)(int x),但習(xí)慣上一般不這樣。 */
int main()
{
FunP = MyFun;
*FunP(10);
return(0);
}
void MyFun(int a)
{
printf("a is %d\n",a);
}

在第7行在函數(shù)指針前加*相當(dāng)取指針的值,在這里理解為將MyFun函數(shù)取出。那么再進(jìn)一步:

#include <stdio.h>
void MyFun(int a); /* 這個聲明也可寫成:void MyFun( int )*/
void (*FunP)(int); /*也可聲明成void(*FunP)(int x),但習(xí)慣上一般不這樣。 */
int main()
{
FunP = MyFun;
FunP(10);
return (0);
}
void MyFun(int a)
{
printf("a is %d\n", a);
}

是的,將FunP前面的*號拿掉也是可以運行的,上面的示例代碼就是函數(shù)指針在C語言中的最常見形態(tài)。之前的例子只是為了讓你更能理解函數(shù)指針,實際開發(fā)中只需要用函數(shù)指針的最終,最常見的形態(tài)即可。

不然代碼中出現(xiàn)之前的形式,其他程序員并不是很熟悉,就成了“騷操作”,雖然不影響運行,但是降低代碼的可閱讀性。

typedef的引入

C語言中typedef關(guān)鍵字作用:復(fù)雜的聲明定義簡單的別名,很明顯我們上面講述的函數(shù)指針就是一個比較復(fù)雜的類型,可以使用typedef關(guān)鍵字將函數(shù)指針的定義簡單化。

#include <stdio.h>
void MyFun(int a); /* 這個聲明也可寫成:void MyFun( int )*/
typedef void (*FunType)(int); /*這樣只是定義一個函數(shù)指針類型 */
FunType FunP; /*然后用FunType類型來聲明全局FunP變量*/
int main()
{
FunP = MyFun;
FunP(10);
return (0);
}
void MyFun(int a)
{
printf("a is %d\n", a);
}

強(qiáng)烈建議使用typedef和函數(shù)指針組合的方式,這是最常見的方式,大家都能看懂的常規(guī)操作。在C語言的教程中typedef用于取別名,形式下:

typedef 舊名字 新名字;

確實也是這樣,但遇到給函數(shù)指針類型、數(shù)組類型等定義別名的時候就要特別區(qū)分了。如:


typedef char ARRAY20[20];
ARRAY20 a1,a2; /* 等價于char a1[20],a2[20]; */

typedef void (*FunType)(int); /*這樣只是定義一個函數(shù)指針類型 */
FunType FunP; /*然后用FunType類型來聲明全局FunP變量*/

別問我為什么,因為我也不知道。

當(dāng)然,并不是說用到了函數(shù)指針就要用typedef定義一下,一般在結(jié)構(gòu)體中使用函數(shù)指針就不會使用typedef,如下:

typedef struct
{
uint8_t data;
void (*FunP)(int);
}Mode_Typedef;

以上均為個人建議,沒有優(yōu)劣,大家根據(jù)自己的習(xí)慣做即可。

函數(shù)指針作為入?yún)?/h4>

既然函數(shù)指針變量是一個變量,當(dāng)然也可以作為某個函數(shù)的參數(shù)來使用的。所以,你還應(yīng)知道函數(shù)指針是如何作為某個函數(shù)的參數(shù)來傳遞使用的。示例代碼如下:

#include <stdio.h>
void MyFun1(int x);
void MyFun2(int x);
void MyFun3(int x);
typedef void (*FunType)(int); /* ②. 定義一個函數(shù)指針類型FunType,與①函數(shù)類型一致 */
void CallMyFun(FunType fp, int x);
int main(int argc, char *argv[])
{
CallMyFun(MyFun1, 10); /* ⑤. 通過CallMyFun函數(shù)分別調(diào)用三個不同的函數(shù) */
CallMyFun(MyFun2, 20);
CallMyFun(MyFun3, 30);
}
void CallMyFun(FunType fp, int x) /* ③. 參數(shù)fp的類型是FunType。*/
{
fp(x); /* ④. 通過fp的指針執(zhí)行傳遞進(jìn)來的函數(shù),注意fp所指的函數(shù)是有一個參數(shù)的。 */
}
void MyFun1(int x) /* ①. 這是個有一個參數(shù)的函數(shù),以下兩個函數(shù)也相同。 */
{
printf("MyFun1:%d\n", x);
}
void MyFun2(int x)
{
printf("MyFun2:%d\n", x);
}
void MyFun3(int x)
{
printf("MyFun3:%d\n", x);
}

運行結(jié)果如下:

可以看到,CallMyFun函數(shù)的參數(shù)是一個指針,當(dāng)這個函數(shù)指針有參數(shù)時,需要通過另外增加一個參數(shù)來保存回調(diào)函數(shù)的參數(shù)值,同理也可以使用多個參數(shù)的函數(shù)指針。

單片機(jī)IAP

在單片機(jī)OTA時常用到函數(shù)指針,代碼如下:

typedef void (*IapFun)(void);//定義一個函數(shù)指針
IapFun Jump_To_Application;//定義函數(shù)指針對象
if (((*(__IO uint32_t*)appxaddr) & 0x2FFE0000 ) == 0x20000000)//檢查地址是否有效
{
Jump_To_Application = (iapfun) * (__IO uint32_t *)(appxaddr + 4);//用戶代碼區(qū)第二個字為程序開始地址(復(fù)位地址)
MSR_MSP(*(__IO uint32_t *)appxaddr);//初始化APP堆棧指針(用戶代碼區(qū)的第一個字用于存放棧頂?shù)刂?
Jump_To_Application();//跳轉(zhuǎn)app
}

這里直接將地址強(qiáng)制轉(zhuǎn)換成函數(shù)指針,然后執(zhí)行這個函數(shù)。appxaddr地址就是新固件存儲的起始地址,appxaddr+4的位置就是新固建中的Reset_Handler函數(shù),相當(dāng)于執(zhí)行了新固件中的Reset_Handler。

責(zé)任編輯:武曉燕 來源: 知曉編程
相關(guān)推薦

2024-02-26 00:00:00

架構(gòu)老化重構(gòu)

2022-09-07 07:27:36

函數(shù)元素

2021-08-27 07:06:10

IOJava抽象

2024-02-20 21:34:16

循環(huán)GolangGo

2023-08-04 08:20:56

DockerfileDocker工具

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信

2023-09-10 21:42:31

2023-06-30 08:18:51

敏捷開發(fā)模式

2023-07-04 08:06:40

數(shù)據(jù)庫容器公有云

2024-01-29 09:01:20

React列表模式

2023-12-06 08:26:19

Service數(shù)據(jù)庫

2022-02-14 07:03:31

網(wǎng)站安全MFA

2022-06-26 09:40:55

Django框架服務(wù)

2022-01-04 12:08:46

設(shè)計接口

2022-10-28 07:27:17

Netty異步Future

2023-04-26 07:30:00

promptUI非結(jié)構(gòu)化

2023-12-28 09:55:08

隊列數(shù)據(jù)結(jié)構(gòu)存儲

2022-11-12 12:33:38

CSS預(yù)處理器Sass

2025-03-27 02:00:00

SPIJava接口
點贊
收藏

51CTO技術(shù)棧公眾號