C語(yǔ)言編程函數(shù)指針入門(mén)精講教程
一、指針引子
示例:我們常常接觸的指針大多有如下幾類(lèi):
整形指針-存放整形地址,指向整形
字符指針-存放字符地址,指向字符
數(shù)組指針-存放數(shù)組地址(注意不是數(shù)組首元素地址),指向數(shù)組
由以上三個(gè)例子,我們能總結(jié)指針的共同點(diǎn):存放某個(gè)類(lèi)型變量的地址,指向那個(gè)類(lèi)型的變量,但是在講函數(shù)指針首先有一個(gè)問(wèn)題:函數(shù)也有地址嗎?我們用一段簡(jiǎn)單的代碼來(lái)驗(yàn)證一下即可。
#include<stdio.h> int Add(int x,int y) { return x+y; } int main() { printf("%p\n",&Add); return 0; }
屏幕上打印出地址:
所以答案是有的,函數(shù)也存在地址,那么也就衍生出了今天的知識(shí)點(diǎn)-函數(shù)指針。
二、使用步驟
1.取函數(shù)地址
我們知道&數(shù)組名,取出的是數(shù)組的地址。單獨(dú)一個(gè)數(shù)組名,取出的是數(shù)組首元素的地址。但是對(duì)于函數(shù)來(lái)說(shuō):函數(shù)名==&函數(shù)名
我們代碼驗(yàn)證一下(示例):
#include<stdio.h> int Add(int x,int y) { return x+y; } int main() { printf("%p\n",&Add); printf("%p\n",Add); return 0; }
顯然,打印出來(lái)的地址是一樣的,但是這個(gè)時(shí)候也會(huì)有同學(xué)跳出來(lái)說(shuō):“那數(shù)組名和&數(shù)組名打印出來(lái)的地址還一樣呢,但意義明顯不一樣啊”。但是你想想,函數(shù)也沒(méi)有首元素等其他玩意啊,它就是它本身啊,它也不會(huì)出現(xiàn)什么函數(shù)首元素啊。
所以再次聲明:
在函數(shù)指針這一塊 函數(shù)名==&函數(shù)名,它的意義和值,都是一樣的
2.創(chuàng)建函數(shù)指針
我們知道,數(shù)組指針用來(lái)存放數(shù)組地址,整形指針用來(lái)存放整形地址。。。函數(shù)指針也不例外,它用來(lái)存放函數(shù)地址,我們現(xiàn)在定義一個(gè)p來(lái)存放Add地址,那它的類(lèi)型怎么創(chuàng)建?我們來(lái)看一下具體步驟:
1.p是一個(gè)指針對(duì)吧,給它一個(gè)*是不是必須的 p變成了 * p。為了確保 * 和 p結(jié)合(如果沒(méi)有括號(hào),*或者p有可能會(huì)與其他的一些符號(hào)結(jié)合,具體參見(jiàn)符號(hào)優(yōu)先級(jí))那我在 * p外面加一個(gè)括號(hào)便于觀看也沒(méi)有問(wèn)題吧,也就是(*p)
2.那函數(shù)總得有參數(shù)啊,比如這里是Add(int x,int y)。參數(shù)x和y的類(lèi)型是int
你指針指向的函數(shù)是不是要找一下它的參數(shù)。所以(*p)(int,int)
3.那函數(shù)還有一個(gè)性質(zhì)啊,有沒(méi)有返回值,要是有的話(huà),類(lèi)型呢? 這里以Add為例,它是返回int型,所以我們指針也返回int 型 即int(*p)(int,int)
到這里Add函數(shù)指針的類(lèi)型就創(chuàng)建完成啦即為*int(p)(int ,int)
需要注意的是:不同函數(shù)的參數(shù)類(lèi)型和返回值類(lèi)型是不一樣的,到時(shí)候需要根據(jù)不同函數(shù)對(duì)類(lèi)型進(jìn)行轉(zhuǎn)換,這里只是以Add函數(shù)為例,其他函數(shù)以此類(lèi)推
ps:一個(gè)快速判別類(lèi)型的方法——去掉變量的名字,剩下的就是類(lèi)型
代碼如下(示例):
int a = 10;//去掉a 類(lèi)型int int arr[10] = { 0 };//去掉arr 類(lèi)型int [10] int(*parr)[10] = &arr;//去掉parr 類(lèi)型int(*)[10],數(shù)組指針,指向一個(gè)10int型元素的數(shù)組 int(*pf)(int, int) = &Add;//去掉pf 類(lèi)型int(*)(int,int)
3.通過(guò)函數(shù)指針調(diào)用函數(shù)的兩種方法
法一:
我們平時(shí)在調(diào)用函數(shù)的時(shí)候,一般就是函數(shù)名( ,)然后把參數(shù)傳進(jìn)括號(hào)即可,那我們現(xiàn)在有函數(shù)指針了呀,指針怎么使用?p不是指向了函數(shù)Add嘛,我們用*解引用指針,得到的是地址里的東西,也就是說(shuō) *p==Add,用 * p(,)來(lái)傳參也可以實(shí)現(xiàn)Add函數(shù)的調(diào)用。代碼如下:
#include<stdio.h> int Add(int x, int y) { return x + y; } int main() { int ret = Add(2, 3); printf("%d\n", ret);//ret=5 int(*p)(int, int) = &Add;//p是一個(gè)指向函數(shù)Add的指針 ret = (*p)(3, 3);//ret=6 //p指向Add,對(duì)p解引用就是Add //簡(jiǎn)言之:*p=Add //我們并不總是可以拿到變量,有時(shí)是拿到變量的地址 //對(duì)應(yīng)函數(shù)指針同樣的道理,有時(shí)不直接給你函數(shù),給你函數(shù)地址,就這樣調(diào)用 printf("%d\n", ret); }
法二:
我們?cè)诙?1取函數(shù)地址那一塊介紹了,在函數(shù)指針這一塊,函數(shù)名==&函數(shù)名, 也就是說(shuō)創(chuàng)建函數(shù)指針的時(shí)候可以這樣寫(xiě):int(*p)(int, int) = Add,Add是賦給了p啊,你也可以認(rèn)為:p就是Add。你可以這樣理解,法一是int(*p)(int, int) = &Add,是把Add的地址給p,所以用p來(lái)調(diào)用函數(shù)要解引用一下,但是法二p就是Add,那不用解引用了,直接調(diào)用。代碼如下:
#include<stdio.h> int Add(int x, int y) { return x + y; } int main() { //我們由前面的知識(shí)知道:函數(shù)add取地址時(shí),add=&add int(*p)(int, int) = Add;//把Add賦給p,這里p即可看做Add //與法一不同的是,法一將&Add賦給p,p是Add的地址,所以要解引用,這里p就可以看做是Add本身,可以不解引用 int ret = p(3, 6); printf("%d", ret); }//如果是為了方便理解,一般是用第一種方法,如果是為了操作方便,可以用第二種方法
三、函數(shù)指針進(jìn)階
大家來(lái)看這樣一個(gè)代碼( * (void(*)() ) 0)(),乍一看非常復(fù)雜,我們來(lái)細(xì)化一下
1 . ( * (void( * )() ) 0)() 我們抽出加粗部分
這是我們熟悉的老朋友:void( * )(),這不就是一個(gè)函數(shù)指針嘛,該函數(shù)無(wú)參,返回類(lèi)型void
2 . (void( * )() ) 0是什么?我們聯(lián)想一下(int)3.14,不就是對(duì)3.14強(qiáng)制類(lèi)型轉(zhuǎn)換嘛,將3.14這個(gè)浮點(diǎn)型強(qiáng)制轉(zhuǎn)換成整形。這里同樣的道理,是將整形0強(qiáng)制轉(zhuǎn)換成類(lèi)型為void( * )()的一個(gè)函數(shù)指針
3 .現(xiàn)在有了(void( * )() ) 0,我們?cè)谶@個(gè)東西前面加一個(gè) *,這個(gè)是什么意思,我們知道(void( * )() ) 0已經(jīng)被轉(zhuǎn)換成一個(gè)指針(指針即地址)了,地址前面加一個(gè) *表示解引用,取出地址里的東西,也就是找到了那個(gè)函數(shù)
4 .(void( * )() ) 0表示那個(gè)函數(shù)那再在后面加一個(gè)()即是對(duì)函數(shù)的調(diào)用,也就是( * (void(*)() ) 0)()
總結(jié)
提示:本文介紹了函數(shù)指針的原理和多種使用方法,對(duì)于函數(shù)指針想要進(jìn)階提升的小伙伴一定要認(rèn)真研讀本文中的進(jìn)階題目,指針是一個(gè)大頭,但相信堅(jiān)持不懈的你一定可以戰(zhàn)勝它,加油!
更多關(guān)于C語(yǔ)言函數(shù)指針的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺析設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用
這篇文章主要介紹了設(shè)計(jì)模式中的代理模式在C++編程中的運(yùn)用,代理模式最大的好處就是實(shí)現(xiàn)了邏輯和實(shí)現(xiàn)的徹底解耦,需要的朋友可以參考下2016-03-03C語(yǔ)言容易被忽視的函數(shù)設(shè)計(jì)原則基礎(chǔ)
C語(yǔ)言的設(shè)計(jì)目標(biāo)是提供一種能以簡(jiǎn)易的方式編譯、處理低級(jí)存儲(chǔ)器、產(chǎn)生少量的機(jī)器碼以及不需要任何運(yùn)行環(huán)境支持便能運(yùn)行的編程語(yǔ)言.那么C語(yǔ)言函數(shù)設(shè)計(jì)的一般原則和技巧都是怎樣的呢,下面帶你了解2022-04-04C語(yǔ)言實(shí)現(xiàn)五子棋對(duì)戰(zhàn)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)五子棋對(duì)戰(zhàn)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05linux c程序中獲取shell腳本輸出的實(shí)現(xiàn)方法
以下是對(duì)在linux下c程序中獲取shell腳本輸出的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-08-08C++實(shí)現(xiàn)哈夫曼樹(shù)簡(jiǎn)單創(chuàng)建與遍歷的方法
這篇文章主要介紹了C++實(shí)現(xiàn)哈夫曼樹(shù)簡(jiǎn)單創(chuàng)建與遍歷的方法,對(duì)于C++算法的學(xué)習(xí)來(lái)說(shuō)不失為一個(gè)很好的借鑒實(shí)例,需要的朋友可以參考下2014-07-07C/C++實(shí)現(xiàn)crc碼計(jì)算和校驗(yàn)
循環(huán)冗余校驗(yàn)(Cyclic Redundancy Check, CRC)是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或計(jì)算機(jī)文件等數(shù)據(jù)產(chǎn)生簡(jiǎn)短固定位數(shù)校驗(yàn)碼的一種信道編碼技術(shù)。本文主要介紹了C++實(shí)現(xiàn)crc碼計(jì)算和校驗(yàn)的方法,需要的可以參考一下2023-03-03C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹
這篇文章主要介紹了C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09