成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我們一起聊聊指針與函數

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

指針函數

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

int *plusfunction(int a,int b);

當然也可以寫成如下格式:

int* plusfunction(int a,int b);

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

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

#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);
}

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

不過我有個疑問,使用指針函數,和函數入參是指針有什么好處呢???

#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í)行也是沒問題的啊,當然我也發(fā)現了指針函數的好處,就是可以把函數作為另一個函數的入參。

testfunction(plusfunction(1,2));

在這點上用第二種方法,將指針作為函數入參是不行的。

還有,將指針作為函數入參前需要向指針申請內存,而指針函數卻不用。

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

函數指針

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

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

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

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

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

#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);是一樣的,在這里強烈建議沒有看過《指針與數組》的同學,先看一下。在教材和資料中,都會講到數組名就是指向數組第一個數據的常量指針。從上面例子看到,函數名貌似也是“常量指針”。數組中,可以將數組名賦給一個指針,然后通過指針訪問數組中的內容,那么我們就可以定義一個函數指針,將函數名賦給函數指針,通過這個函數指針調用函數。

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

在第7行在函數指針前加*相當取指針的值,在這里理解為將MyFun函數取出。那么再進一步:

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

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

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

typedef的引入

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

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

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

typedef 舊名字 新名字;

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


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

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

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

當然,并不是說用到了函數指針就要用typedef定義一下,一般在結構體中使用函數指針就不會使用typedef,如下:

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

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

函數指針作為入參

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

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

運行結果如下:

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

單片機IAP

在單片機OTA時常用到函數指針,代碼如下:

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

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

責任編輯:武曉燕 來源: 知曉編程
相關推薦

2024-02-26 00:00:00

架構老化重構

2021-08-27 07:06:10

IOJava抽象

2024-02-20 21:34:16

循環(huán)GolangGo

2023-08-10 08:28:46

網絡編程通信

2023-08-04 08:20:56

DockerfileDocker工具

2023-06-30 08:18:51

敏捷開發(fā)模式

2023-09-10 21:42:31

2022-05-24 08:21:16

數據安全API

2022-09-07 07:27:36

函數元素

2024-01-29 09:01:20

React列表模式

2023-07-04 08:06:40

數據庫容器公有云

2023-12-06 08:26:19

Service數據庫

2022-11-12 12:33:38

CSS預處理器Sass

2025-03-27 02:00:00

SPIJava接口

2024-02-26 00:00:00

Go性能工具

2023-12-28 09:55:08

隊列數據結構存儲

2022-01-04 12:08:46

設計接口

2023-07-27 07:46:51

SAFe團隊測試

2023-04-26 07:30:00

promptUI非結構化

2022-06-26 09:40:55

Django框架服務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本又色又爽又黄的大片 | 中文无吗 | 国产精品久久久久久久久久久久 | 午夜视频大全 | 免费毛片www com cn | caoporn国产精品免费公开 | 亚州精品天堂中文字幕 | 国产精品免费在线 | 视频一区二区在线观看 | 久久国产一区 | www.欧美视频 | 激情欧美一区二区三区中文字幕 | 国产精品一区二区欧美 | 国产毛片毛片 | 精品日韩一区 | 日本黄色片免费在线观看 | 亚洲一区二区在线视频 | 亚洲国产午夜 | 亚洲狠狠丁香婷婷综合久久久 | 在线视频 欧美日韩 | 日韩在线视频一区二区三区 | 小h片免费观看久久久久 | 国产成人亚洲精品自产在线 | 欧美在线观看一区 | 久久久精 | 日韩欧美高清dvd碟片 | 久久精品久久久久久 | 一区二区三区视频在线观看 | 一区视频| 精品国产乱码久久久久久闺蜜 | 日韩欧美中文字幕在线观看 | 国产一区二区在线播放视频 | 黄色在线免费观看 | 久久亚洲经典 | 自拍偷拍亚洲一区 | 一级欧美一级日韩片免费观看 | 亚洲国产精品久久 | 99精品久久 | 久久无毛 | 草b视频 | av免费看片|